From f9ad3e103c75a1de71b0bf87a14acdc718c324ed Mon Sep 17 00:00:00 2001 From: Ayush Chakraborty Date: Fri, 6 Dec 2024 14:22:53 -0500 Subject: [PATCH 1/2] integrated firebase sso and user profiles --- .gitignore | 2 + MusicalCaneGame.xcodeproj/project.pbxproj | 61 + MusicalCaneGame/AppDelegate.swift | 3 + MusicalCaneGame/AuthManager.swift | 153 + MusicalCaneGame/DBInterface.swift | 29 +- MusicalCaneGame/FirebaseManager.swift | 79 + MusicalCaneGame/MainViewController.swift | 6 + MusicalCaneGame/MusicalCaneGame.entitlements | 10 + Podfile.lock | 33 +- Pods/Bolts-Swift/LICENSE | 30 + Pods/Bolts-Swift/README.md | 198 + .../Sources/BoltsSwift/Errors.swift | 34 + .../Sources/BoltsSwift/Executor.swift | 138 + .../BoltsSwift/Task+ContinueWith.swift | 222 + .../Sources/BoltsSwift/Task+Delay.swift | 32 + .../Sources/BoltsSwift/Task+WhenAll.swift | 109 + .../Sources/BoltsSwift/Task+WhenAny.swift | 58 + .../Bolts-Swift/Sources/BoltsSwift/Task.swift | 308 + .../BoltsSwift/TaskCompletionSource.swift | 120 + .../Classes/ColorPickerController.swift | 205 + .../ColorPickerControllerProtocol.swift | 37 + .../Classes/ColorPickerDelegate.swift | 63 + .../ColorPaletteDelegate.swift | 39 + .../ColorSliderDelegate.swift | 34 + .../ComponentSliderDelegates.swift | 89 + .../RadialHSBPaletteDelegate.swift | 132 + .../RectangularHSBPaletteDelegate.swift | 94 + .../Controls/AbstractColorControl.swift | 107 + .../Controls/AdjustedHitBoxColorControl.swift | 84 + .../Classes/Controls/ColorControl.swift | 70 + .../Controls/ColorPaletteControl.swift | 155 + .../Controls/ColorPreviewWithHex.swift | 219 + .../Classes/Controls/ColorSliderControl.swift | 195 + .../Controls/ComponentSliderControls.swift | 91 + .../Controls/ControlWithThumbView.swift | 89 + .../Classes/Controls/PaletteControls.swift | 87 + .../CustomColorPickerViewController.swift | 170 + .../DefaultColorPickerViewController.swift | 257 + .../FlexColorPicker/Classes/FlexColorPicker.h | 19 + .../FlexColorPicker/Classes/HSBColor.swift | 165 + .../Classes/Utilities/CGPointExtension.swift | 41 + .../Classes/Utilities/CGRectExtension.swift | 35 + .../LimitedGestureViewDelegate.swift | 33 + .../Classes/Utilities/UIColorExtension.swift | 140 + .../Classes/Utilities/UIImageExtension.swift | 57 + .../Utilities/UIImageViewExtension.swift | 85 + .../Classes/Utilities/UIViewExtension.swift | 80 + .../Classes/Views/CircleShapedView.swift | 47 + .../Views/ColorControlContentView.swift | 45 + .../Classes/Views/ColorPickerThumbView.swift | 169 + .../Classes/Views/GradientView.swift | 84 + .../Views/LimitedGestureCircleView.swift | 41 + .../Views/PaletteAwareScrollView.swift | 59 + .../Classes/Views/UIViewWithCommonInit.swift | 55 + Pods/FlexColorPicker/LICENSE | 21 + Pods/FlexColorPicker/README.md | 217 + Pods/MBProgressHUD/LICENSE | 19 + Pods/MBProgressHUD/MBProgressHUD.h | 411 + Pods/MBProgressHUD/MBProgressHUD.m | 1194 ++ Pods/MBProgressHUD/README.mdown | 138 + Pods/Manifest.lock | 33 +- Pods/MetaWear/LICENSE.md | 10 + Pods/MetaWear/MetaWear/Core/Bridging.swift | 57 + Pods/MetaWear/MetaWear/Core/CBUUID.swift | 52 + .../MetaWear/Core/DeviceInformation.swift | 68 + Pods/MetaWear/MetaWear/Core/LogDelegate.swift | 73 + .../MetaWear/Core/MblMwGattChar.swift | 68 + Pods/MetaWear/MetaWear/Core/MetaWear.swift | 640 + .../MetaWear/MetaWear/Core/MetaWearData.swift | 130 + .../MetaWear/Core/MetaWearScanner.swift | 270 + .../MetaWear/Core/String+VersionCompare.swift | 67 + .../bindings/swift/cbindings.swift | 44 + .../src/metawear/core/anonymous_datasignal.h | 32 + .../metawear/core/anonymous_datasignal_fwd.h | 27 + .../core/cpp/anonymous_datasignal.cpp | 12 + .../core/cpp/anonymous_datasignal_private.h | 11 + .../src/metawear/core/cpp/constant.h | 5 + .../src/metawear/core/cpp/datainterpreter.h | 80 + .../src/metawear/core/cpp/datasignal.cpp | 254 + .../metawear/core/cpp/datasignal_private.h | 49 + .../src/metawear/core/cpp/debug.cpp | 155 + .../src/metawear/core/cpp/debug_private.h | 4 + .../src/metawear/core/cpp/event.cpp | 166 + .../src/metawear/core/cpp/event_private.h | 35 + .../src/metawear/core/cpp/event_register.h | 8 + .../src/metawear/core/cpp/logging.cpp | 962 ++ .../src/metawear/core/cpp/logging_private.h | 17 + .../src/metawear/core/cpp/logging_register.h | 20 + .../src/metawear/core/cpp/macro.cpp | 130 + .../src/metawear/core/cpp/macro_private.h | 5 + .../src/metawear/core/cpp/macro_register.h | 10 + .../src/metawear/core/cpp/metawearboard_def.h | 67 + .../metawear/core/cpp/metawearboard_macro.h | 16 + .../src/metawear/core/cpp/moduleinfo.cpp | 46 + .../src/metawear/core/cpp/moduleinfo.h | 18 + .../src/metawear/core/cpp/register.h | 7 + .../src/metawear/core/cpp/responseheader.cpp | 70 + .../src/metawear/core/cpp/responseheader.h | 35 + .../src/metawear/core/cpp/settings.cpp | 282 + .../src/metawear/core/cpp/settings_private.h | 8 + .../src/metawear/core/cpp/settings_register.h | 19 + .../src/metawear/core/cpp/timer.cpp | 129 + .../src/metawear/core/cpp/timer_private.h | 16 + .../src/metawear/core/cpp/timer_register.h | 13 + .../src/metawear/core/cpp/version.cpp | 100 + .../src/metawear/core/cpp/version.h | 24 + .../MetaWear-SDK-Cpp/src/metawear/core/data.h | 52 + .../src/metawear/core/datasignal.h | 69 + .../src/metawear/core/datasignal_fwd.h | 16 + .../src/metawear/core/debug.h | 94 + .../src/metawear/core/event.h | 48 + .../src/metawear/core/event_fwd.h | 25 + .../src/metawear/core/logging.h | 198 + .../src/metawear/core/logging_fwd.h | 22 + .../src/metawear/core/macro.h | 51 + .../src/metawear/core/metawearboard.h | 164 + .../src/metawear/core/metawearboard_fwd.h | 31 + .../src/metawear/core/model.h | 26 + .../src/metawear/core/module.h | 38 + .../src/metawear/core/settings.h | 194 + .../src/metawear/core/status.h | 26 + .../src/metawear/core/timer.h | 71 + .../src/metawear/core/timer_fwd.h | 23 + .../src/metawear/core/types.h | 113 + .../src/metawear/dfu/cpp/dfu_operations.cpp | 343 + .../src/metawear/dfu/cpp/dfu_operations.h | 99 + .../dfu/cpp/dfu_operations_details.cpp | 100 + .../metawear/dfu/cpp/dfu_operations_details.h | 30 + .../src/metawear/dfu/cpp/dfu_utility.cpp | 4 + .../src/metawear/dfu/cpp/dfu_utility.h | 90 + .../src/metawear/dfu/cpp/file_operations.cpp | 171 + .../src/metawear/dfu/cpp/file_operations.h | 39 + .../src/metawear/dfu/cpp/json.hpp | 10036 ++++++++++++++++ .../src/metawear/dfu/cpp/miniz.cpp | 7557 ++++++++++++ .../src/metawear/dfu/cpp/miniz.h | 1328 ++ .../generator/cpp/CSharpGenerator.cpp | 18 + .../metawear/generator/cpp/CSharpGenerator.h | 13 + .../generator/cpp/JavaScriptGenerator.cpp | 292 + .../generator/cpp/JavaScriptGenerator.h | 13 + .../generator/cpp/PythonGenerator.cpp | 341 + .../metawear/generator/cpp/PythonGenerator.h | 13 + .../metawear/generator/cpp/SwiftGenerator.cpp | 40 + .../metawear/generator/cpp/SwiftGenerator.h | 13 + .../src/metawear/generator/cpp/common.cpp | 36 + .../src/metawear/generator/cpp/common.h | 8 + .../src/metawear/impl/cpp/datainterpreter.cpp | 496 + .../src/metawear/impl/cpp/metawearboard.cpp | 896 ++ .../src/metawear/peripheral/cpp/haptic.cpp | 23 + .../src/metawear/peripheral/cpp/ibeacon.cpp | 70 + .../src/metawear/peripheral/cpp/led.cpp | 75 + .../src/metawear/peripheral/cpp/neopixel.cpp | 71 + .../src/metawear/peripheral/haptic.h | 33 + .../src/metawear/peripheral/ibeacon.h | 78 + .../src/metawear/peripheral/led.h | 92 + .../src/metawear/peripheral/neopixel.h | 116 + .../metawear/peripheral/peripheral_common.h | 4 + .../src/metawear/platform/btle_connection.h | 92 + .../metawear/platform/cpp/async_creator.cpp | 16 + .../src/metawear/platform/cpp/async_creator.h | 16 + .../metawear/platform/cpp/concurrent_queue.h | 73 + .../src/metawear/platform/cpp/memory.cpp | 9 + .../src/metawear/platform/cpp/task.cpp | 3 + .../src/metawear/platform/cpp/task.h | 7 + .../src/metawear/platform/cpp/threadpool.cpp | 47 + .../src/metawear/platform/cpp/threadpool.h | 12 + .../src/metawear/platform/dllmarker.h | 37 + .../src/metawear/platform/memory.h | 22 + .../src/metawear/processor/accounter.h | 38 + .../src/metawear/processor/accumulator.h | 45 + .../src/metawear/processor/average.h | 60 + .../src/metawear/processor/buffer.h | 27 + .../src/metawear/processor/comparator.h | 148 + .../src/metawear/processor/counter.h | 48 + .../metawear/processor/cpp/dataprocessor.cpp | 668 + .../processor/cpp/dataprocessor_config.cpp | 766 ++ .../processor/cpp/dataprocessor_config.h | 140 + .../processor/cpp/dataprocessor_private.h | 84 + .../processor/cpp/dataprocessor_register.h | 11 + .../src/metawear/processor/dataprocessor.h | 45 + .../metawear/processor/dataprocessor_fwd.h | 23 + .../src/metawear/processor/delta.h | 54 + .../src/metawear/processor/fuser.h | 30 + .../src/metawear/processor/math.h | 86 + .../src/metawear/processor/packer.h | 28 + .../src/metawear/processor/passthrough.h | 57 + .../src/metawear/processor/processor_common.h | 5 + .../src/metawear/processor/pulse.h | 49 + .../src/metawear/processor/rms.h | 27 + .../src/metawear/processor/rss.h | 27 + .../src/metawear/processor/sample.h | 37 + .../src/metawear/processor/threshold.h | 48 + .../src/metawear/processor/time.h | 44 + .../src/metawear/sensor/accelerometer.h | 95 + .../src/metawear/sensor/accelerometer_bosch.h | 781 ++ .../metawear/sensor/accelerometer_mma8452q.h | 162 + .../src/metawear/sensor/ambientlight_ltr329.h | 104 + .../src/metawear/sensor/barometer_bosch.h | 153 + .../metawear/sensor/colordetector_tcs34725.h | 74 + .../src/metawear/sensor/conductance.h | 49 + .../src/metawear/sensor/cpp/accelerometer.cpp | 262 + .../sensor/cpp/accelerometer_bosch.cpp | 1642 +++ .../sensor/cpp/accelerometer_bosch_private.h | 26 + .../sensor/cpp/accelerometer_bosch_register.h | 57 + .../sensor/cpp/accelerometer_mma8452q.cpp | 369 + .../cpp/accelerometer_mma8452q_private.h | 15 + .../cpp/accelerometer_mma8452q_register.h | 21 + .../sensor/cpp/accelerometer_private.h | 13 + .../sensor/cpp/ambientlight_ltr329.cpp | 107 + .../sensor/cpp/ambientlight_ltr329_private.h | 11 + .../sensor/cpp/ambientlight_ltr329_register.h | 7 + .../metawear/sensor/cpp/barometer_bosch.cpp | 158 + .../sensor/cpp/barometer_bosch_private.h | 10 + .../sensor/cpp/barometer_bosch_register.h | 8 + .../sensor/cpp/colordetector_tcs34725.cpp | 104 + .../cpp/colordetector_tcs34725_private.h | 11 + .../cpp/colordetector_tcs34725_register.h | 6 + .../src/metawear/sensor/cpp/conductance.cpp | 50 + .../metawear/sensor/cpp/conductance_private.h | 5 + .../sensor/cpp/conductance_register.h | 7 + .../src/metawear/sensor/cpp/gpio.cpp | 172 + .../src/metawear/sensor/cpp/gpio_private.h | 23 + .../src/metawear/sensor/cpp/gpio_register.h | 17 + .../src/metawear/sensor/cpp/gyro_bosch.cpp | 311 + .../metawear/sensor/cpp/gyro_bosch_private.h | 14 + .../metawear/sensor/cpp/gyro_bosch_register.h | 18 + .../metawear/sensor/cpp/humidity_bme280.cpp | 45 + .../sensor/cpp/humidity_bme280_private.h | 7 + .../sensor/cpp/humidity_bme280_register.h | 6 + .../sensor/cpp/magnetometer_bmm150.cpp | 122 + .../sensor/cpp/magnetometer_bmm150_private.h | 9 + .../sensor/cpp/magnetometer_bmm150_register.h | 10 + .../sensor/cpp/multichanneltemperature.cpp | 65 + .../cpp/multichanneltemperature_private.h | 8 + .../cpp/multichanneltemperature_register.h | 6 + .../metawear/sensor/cpp/proximity_tsl2671.cpp | 90 + .../sensor/cpp/proximity_tsl2671_private.h | 11 + .../sensor/cpp/proximity_tsl2671_register.h | 6 + .../src/metawear/sensor/cpp/sensor_fusion.cpp | 420 + .../sensor/cpp/sensor_fusion_private.h | 12 + .../sensor/cpp/sensor_fusion_register.h | 19 + .../metawear/sensor/cpp/serialpassthrough.cpp | 144 + .../sensor/cpp/serialpassthrough_private.h | 24 + .../sensor/cpp/serialpassthrough_register.h | 6 + .../src/metawear/sensor/cpp/switch.cpp | 35 + .../src/metawear/sensor/cpp/switch_private.h | 7 + .../src/metawear/sensor/cpp/switch_register.h | 6 + .../src/metawear/sensor/cpp/utils.cpp | 42 + .../src/metawear/sensor/cpp/utils.h | 11 + .../src/metawear/sensor/gpio.h | 130 + .../src/metawear/sensor/gyro_bosch.h | 200 + .../src/metawear/sensor/humidity_bme280.h | 45 + .../src/metawear/sensor/i2c.h | 44 + .../src/metawear/sensor/magnetometer_bmm150.h | 141 + .../metawear/sensor/multichanneltemperature.h | 82 + .../src/metawear/sensor/proximity_tsl2671.h | 85 + .../src/metawear/sensor/sensor_common.h | 5 + .../src/metawear/sensor/sensor_fusion.h | 182 + .../src/metawear/sensor/spi.h | 72 + .../src/metawear/sensor/switch.h | 25 + .../MetaWear-SDK-Cpp/src/module.modulemap | 70 + Pods/MetaWear/README.md | 158 + Pods/PRTween/LICENSE | 8 + Pods/PRTween/README.md | 307 + Pods/PRTween/lib/PRTween.h | 443 + Pods/PRTween/lib/PRTween.m | 1175 ++ Pods/PRTween/lib/PRTweenTimingFunctions.h | 82 + Pods/PRTween/lib/PRTweenTimingFunctions.m | 230 + Pods/Pods.xcodeproj/project.pbxproj | 3368 ++---- .../xcschemes/Bolts-Swift.xcscheme | 58 + .../xcschemes/FlexColorPicker.xcscheme | 58 + .../xcschemes/MBProgressHUD.xcscheme | 58 + .../xcschemes/MetaWear.xcscheme | 58 + .../xcschemes/PRTween.xcscheme | 58 + .../xcschemes/Pods-MusicalCaneGame.xcscheme | 58 + .../xcschemes/SQLite.swift.xcscheme | 58 + .../StaticDataTableViewController.xcscheme | 58 + .../xcschemes/xcschememanagement.plist | 51 + .../StaticDataTableViewController/LICENSE.txt | 201 + Pods/StaticDataTableViewController/README.md | 76 + .../StaticDataTableViewController.h | 60 + .../StaticDataTableViewController.m | 598 + .../Bolts-Swift/Bolts-Swift-Info.plist | 26 + .../Bolts-Swift/Bolts-Swift-dummy.m | 5 + .../Bolts-Swift/Bolts-Swift-prefix.pch | 12 + .../Bolts-Swift/Bolts-Swift-umbrella.h | 16 + .../Bolts-Swift/Bolts-Swift.debug.xcconfig | 14 + .../Bolts-Swift/Bolts-Swift.modulemap | 6 + .../Bolts-Swift/Bolts-Swift.release.xcconfig | 14 + .../FlexColorPicker-Info.plist | 26 + .../FlexColorPicker/FlexColorPicker-dummy.m | 5 + .../FlexColorPicker-prefix.pch | 12 + .../FlexColorPicker-umbrella.h | 17 + .../FlexColorPicker.debug.xcconfig | 14 + .../FlexColorPicker/FlexColorPicker.modulemap | 6 + .../FlexColorPicker.release.xcconfig | 14 + .../MBProgressHUD/MBProgressHUD-Info.plist | 26 + .../MBProgressHUD/MBProgressHUD-dummy.m | 5 + .../MBProgressHUD/MBProgressHUD-prefix.pch | 12 + .../MBProgressHUD/MBProgressHUD-umbrella.h | 17 + .../MBProgressHUD.debug.xcconfig | 13 + .../MBProgressHUD/MBProgressHUD.modulemap | 6 + .../MBProgressHUD.release.xcconfig | 13 + .../MetaWear/MetaWear-Info.plist | 26 + .../MetaWear/MetaWear-dummy.m | 5 + .../MetaWear/MetaWear-prefix.pch | 12 + .../MetaWear/MetaWear-umbrella.h | 16 + .../MetaWear/MetaWear.debug.xcconfig | 18 + .../MetaWear/MetaWear.modulemap | 6 + .../MetaWear/MetaWear.release.xcconfig | 18 + .../PRTween/PRTween-Info.plist | 26 + .../PRTween/PRTween-dummy.m | 5 + .../PRTween/PRTween-prefix.pch | 12 + .../PRTween/PRTween-umbrella.h | 18 + .../PRTween/PRTween.debug.xcconfig | 12 + .../PRTween/PRTween.modulemap | 6 + .../PRTween/PRTween.release.xcconfig | 12 + ...-MusicalCaneGame-acknowledgements.markdown | 32 +- ...ods-MusicalCaneGame-acknowledgements.plist | 38 +- ...me-frameworks-Debug-input-files.xcfilelist | 8 + ...e-frameworks-Debug-output-files.xcfilelist | 7 + ...-frameworks-Release-input-files.xcfilelist | 8 + ...frameworks-Release-output-files.xcfilelist | 7 + .../Pods-MusicalCaneGame-frameworks.sh | 10 +- .../Pods-MusicalCaneGame.debug.xcconfig | 6 +- .../Pods-MusicalCaneGame.release.xcconfig | 6 +- .../SQLite.swift/SQLite.swift.debug.xcconfig | 16 + .../SQLite.swift.release.xcconfig | 16 + .../StaticDataTableViewController-Info.plist | 26 + .../StaticDataTableViewController-dummy.m | 5 + .../StaticDataTableViewController-prefix.pch | 12 + .../StaticDataTableViewController-umbrella.h | 17 + ...aticDataTableViewController.debug.xcconfig | 12 + .../StaticDataTableViewController.modulemap | 6 + ...icDataTableViewController.release.xcconfig | 12 + 334 files changed, 50528 insertions(+), 2531 deletions(-) create mode 100644 MusicalCaneGame/AuthManager.swift create mode 100644 MusicalCaneGame/FirebaseManager.swift create mode 100644 MusicalCaneGame/MusicalCaneGame.entitlements create mode 100644 Pods/Bolts-Swift/LICENSE create mode 100644 Pods/Bolts-Swift/README.md create mode 100644 Pods/Bolts-Swift/Sources/BoltsSwift/Errors.swift create mode 100644 Pods/Bolts-Swift/Sources/BoltsSwift/Executor.swift create mode 100644 Pods/Bolts-Swift/Sources/BoltsSwift/Task+ContinueWith.swift create mode 100644 Pods/Bolts-Swift/Sources/BoltsSwift/Task+Delay.swift create mode 100644 Pods/Bolts-Swift/Sources/BoltsSwift/Task+WhenAll.swift create mode 100644 Pods/Bolts-Swift/Sources/BoltsSwift/Task+WhenAny.swift create mode 100644 Pods/Bolts-Swift/Sources/BoltsSwift/Task.swift create mode 100644 Pods/Bolts-Swift/Sources/BoltsSwift/TaskCompletionSource.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerController.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerControllerProtocol.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerDelegate.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ColorPaletteDelegate.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ColorSliderDelegate.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ComponentSliderDelegates.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/RadialHSBPaletteDelegate.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/RectangularHSBPaletteDelegate.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/AbstractColorControl.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/AdjustedHitBoxColorControl.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorControl.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorPaletteControl.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorPreviewWithHex.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorSliderControl.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ControlWithThumbView.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/PaletteControls.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/CustomColorPickerViewController.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/DefaultColorPickerViewController.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/FlexColorPicker.h create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/HSBColor.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/CGPointExtension.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/CGRectExtension.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/LimitedGestureViewDelegate.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIColorExtension.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIImageExtension.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIImageViewExtension.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIViewExtension.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Views/CircleShapedView.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Views/ColorControlContentView.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Views/ColorPickerThumbView.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Views/GradientView.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Views/LimitedGestureCircleView.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Views/PaletteAwareScrollView.swift create mode 100644 Pods/FlexColorPicker/FlexColorPicker/Classes/Views/UIViewWithCommonInit.swift create mode 100644 Pods/FlexColorPicker/LICENSE create mode 100644 Pods/FlexColorPicker/README.md create mode 100644 Pods/MBProgressHUD/LICENSE create mode 100644 Pods/MBProgressHUD/MBProgressHUD.h create mode 100644 Pods/MBProgressHUD/MBProgressHUD.m create mode 100644 Pods/MBProgressHUD/README.mdown create mode 100644 Pods/MetaWear/LICENSE.md create mode 100644 Pods/MetaWear/MetaWear/Core/Bridging.swift create mode 100644 Pods/MetaWear/MetaWear/Core/CBUUID.swift create mode 100644 Pods/MetaWear/MetaWear/Core/DeviceInformation.swift create mode 100644 Pods/MetaWear/MetaWear/Core/LogDelegate.swift create mode 100644 Pods/MetaWear/MetaWear/Core/MblMwGattChar.swift create mode 100644 Pods/MetaWear/MetaWear/Core/MetaWear.swift create mode 100644 Pods/MetaWear/MetaWear/Core/MetaWearData.swift create mode 100644 Pods/MetaWear/MetaWear/Core/MetaWearScanner.swift create mode 100644 Pods/MetaWear/MetaWear/Core/String+VersionCompare.swift create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/bindings/swift/cbindings.swift create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/anonymous_datasignal.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/anonymous_datasignal_fwd.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/constant.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datainterpreter.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/metawearboard_def.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/metawearboard_macro.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/data.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/datasignal.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/datasignal_fwd.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/debug.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/event.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/event_fwd.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/logging.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/logging_fwd.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/macro.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/metawearboard.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/metawearboard_fwd.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/model.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/module.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/settings.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/status.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/timer.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/timer_fwd.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/types.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/json.hpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/CSharpGenerator.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/CSharpGenerator.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/JavaScriptGenerator.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/JavaScriptGenerator.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/PythonGenerator.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/PythonGenerator.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/SwiftGenerator.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/SwiftGenerator.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/common.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/common.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/datainterpreter.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/metawearboard.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/haptic.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/ibeacon.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/led.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/neopixel.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/haptic.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/ibeacon.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/led.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/neopixel.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/peripheral_common.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/btle_connection.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/concurrent_queue.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/memory.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/dllmarker.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/memory.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/accounter.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/accumulator.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/average.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/buffer.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/comparator.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/counter.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/dataprocessor.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/dataprocessor_fwd.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/delta.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/fuser.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/math.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/packer.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/passthrough.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/processor_common.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/pulse.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/rms.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/rss.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/sample.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/threshold.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/time.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer_bosch.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer_mma8452q.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/ambientlight_ltr329.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/barometer_bosch.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/colordetector_tcs34725.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/conductance.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch_private.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch_register.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.cpp create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/gpio.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/gyro_bosch.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/humidity_bme280.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/i2c.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/magnetometer_bmm150.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/multichanneltemperature.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/proximity_tsl2671.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/sensor_common.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/sensor_fusion.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/spi.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/switch.h create mode 100644 Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/module.modulemap create mode 100644 Pods/MetaWear/README.md create mode 100644 Pods/PRTween/LICENSE create mode 100644 Pods/PRTween/README.md create mode 100755 Pods/PRTween/lib/PRTween.h create mode 100755 Pods/PRTween/lib/PRTween.m create mode 100755 Pods/PRTween/lib/PRTweenTimingFunctions.h create mode 100755 Pods/PRTween/lib/PRTweenTimingFunctions.m create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/Bolts-Swift.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/FlexColorPicker.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/MBProgressHUD.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/MetaWear.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/PRTween.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/Pods-MusicalCaneGame.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/SQLite.swift.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/StaticDataTableViewController.xcscheme create mode 100644 Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Pods/StaticDataTableViewController/LICENSE.txt create mode 100644 Pods/StaticDataTableViewController/README.md create mode 100755 Pods/StaticDataTableViewController/StaticDataTableViewController.h create mode 100755 Pods/StaticDataTableViewController/StaticDataTableViewController.m create mode 100644 Pods/Target Support Files/Bolts-Swift/Bolts-Swift-Info.plist create mode 100644 Pods/Target Support Files/Bolts-Swift/Bolts-Swift-dummy.m create mode 100644 Pods/Target Support Files/Bolts-Swift/Bolts-Swift-prefix.pch create mode 100644 Pods/Target Support Files/Bolts-Swift/Bolts-Swift-umbrella.h create mode 100644 Pods/Target Support Files/Bolts-Swift/Bolts-Swift.debug.xcconfig create mode 100644 Pods/Target Support Files/Bolts-Swift/Bolts-Swift.modulemap create mode 100644 Pods/Target Support Files/Bolts-Swift/Bolts-Swift.release.xcconfig create mode 100644 Pods/Target Support Files/FlexColorPicker/FlexColorPicker-Info.plist create mode 100644 Pods/Target Support Files/FlexColorPicker/FlexColorPicker-dummy.m create mode 100644 Pods/Target Support Files/FlexColorPicker/FlexColorPicker-prefix.pch create mode 100644 Pods/Target Support Files/FlexColorPicker/FlexColorPicker-umbrella.h create mode 100644 Pods/Target Support Files/FlexColorPicker/FlexColorPicker.debug.xcconfig create mode 100644 Pods/Target Support Files/FlexColorPicker/FlexColorPicker.modulemap create mode 100644 Pods/Target Support Files/FlexColorPicker/FlexColorPicker.release.xcconfig create mode 100644 Pods/Target Support Files/MBProgressHUD/MBProgressHUD-Info.plist create mode 100644 Pods/Target Support Files/MBProgressHUD/MBProgressHUD-dummy.m create mode 100644 Pods/Target Support Files/MBProgressHUD/MBProgressHUD-prefix.pch create mode 100644 Pods/Target Support Files/MBProgressHUD/MBProgressHUD-umbrella.h create mode 100644 Pods/Target Support Files/MBProgressHUD/MBProgressHUD.debug.xcconfig create mode 100644 Pods/Target Support Files/MBProgressHUD/MBProgressHUD.modulemap create mode 100644 Pods/Target Support Files/MBProgressHUD/MBProgressHUD.release.xcconfig create mode 100644 Pods/Target Support Files/MetaWear/MetaWear-Info.plist create mode 100644 Pods/Target Support Files/MetaWear/MetaWear-dummy.m create mode 100644 Pods/Target Support Files/MetaWear/MetaWear-prefix.pch create mode 100644 Pods/Target Support Files/MetaWear/MetaWear-umbrella.h create mode 100644 Pods/Target Support Files/MetaWear/MetaWear.debug.xcconfig create mode 100644 Pods/Target Support Files/MetaWear/MetaWear.modulemap create mode 100644 Pods/Target Support Files/MetaWear/MetaWear.release.xcconfig create mode 100644 Pods/Target Support Files/PRTween/PRTween-Info.plist create mode 100644 Pods/Target Support Files/PRTween/PRTween-dummy.m create mode 100644 Pods/Target Support Files/PRTween/PRTween-prefix.pch create mode 100644 Pods/Target Support Files/PRTween/PRTween-umbrella.h create mode 100644 Pods/Target Support Files/PRTween/PRTween.debug.xcconfig create mode 100644 Pods/Target Support Files/PRTween/PRTween.modulemap create mode 100644 Pods/Target Support Files/PRTween/PRTween.release.xcconfig create mode 100644 Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Debug-input-files.xcfilelist create mode 100644 Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Debug-output-files.xcfilelist create mode 100644 Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Release-input-files.xcfilelist create mode 100644 Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Release-output-files.xcfilelist create mode 100644 Pods/Target Support Files/SQLite.swift/SQLite.swift.debug.xcconfig create mode 100644 Pods/Target Support Files/SQLite.swift/SQLite.swift.release.xcconfig create mode 100644 Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-Info.plist create mode 100644 Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-dummy.m create mode 100644 Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-prefix.pch create mode 100644 Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-umbrella.h create mode 100644 Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.debug.xcconfig create mode 100644 Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.modulemap create mode 100644 Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.release.xcconfig diff --git a/.gitignore b/.gitignore index 8a85b55..f65ec9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .DS_Store _DS_Store +MusicalCaneGame/GoogleService-Info.plist + # Created by https://www.gitignore.io/api/swift,xcode # Edit at https://www.gitignore.io/?templates=swift,xcode diff --git a/MusicalCaneGame.xcodeproj/project.pbxproj b/MusicalCaneGame.xcodeproj/project.pbxproj index 18f7da2..8b28668 100644 --- a/MusicalCaneGame.xcodeproj/project.pbxproj +++ b/MusicalCaneGame.xcodeproj/project.pbxproj @@ -30,6 +30,13 @@ 98182389211A30EF006A28F7 /* BeaconTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98182388211A30EF006A28F7 /* BeaconTableViewCell.swift */; }; 981823A3211A3894006A28F7 /* White.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 9818239D211A3894006A28F7 /* White.jpg */; }; 98A02ACD2CEE3BFE00BEA33D /* SensorManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A02ACC2CEE3BFD00BEA33D /* SensorManagerView.swift */; }; + 9822A1C82CDA9AD800CFFD13 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9822A1C72CDA9AD800CFFD13 /* GoogleService-Info.plist */; }; + 9822A1CB2CDAA4C900CFFD13 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 9822A1CA2CDAA4C900CFFD13 /* FirebaseAnalytics */; }; + 9822A1CD2CDAA7AB00CFFD13 /* FirebaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9822A1CC2CDAA7A500CFFD13 /* FirebaseManager.swift */; }; + 9822A1CF2CDAA8C000CFFD13 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 9822A1CE2CDAA8C000CFFD13 /* FirebaseFirestore */; }; + 9822A1D12CE3CD6700CFFD13 /* AuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9822A1D02CE3CD6000CFFD13 /* AuthManager.swift */; }; + 9822A1D32CE3CDE900CFFD13 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 9822A1D22CE3CDE900CFFD13 /* FirebaseAuth */; }; + 9822A1D52CE3CE1C00CFFD13 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 9822A1D42CE3CE1C00CFFD13 /* FirebaseAuth */; }; 98B8DB922112359A00BEB719 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4959A5B32111F811006193E6 /* MobileCoreServices.framework */; }; 98B8DBBB211340CA00BEB719 /* MediaToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98B8DBBA211340CA00BEB719 /* MediaToolbox.framework */; }; 98C4ADDC2CED794F00CE98FA /* SensorDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C4ADDB2CED794F00CE98FA /* SensorDriver.swift */; }; @@ -72,6 +79,10 @@ 98182388211A30EF006A28F7 /* BeaconTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BeaconTableViewCell.swift; sourceTree = ""; }; 9818239D211A3894006A28F7 /* White.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = White.jpg; sourceTree = ""; }; 98A02ACC2CEE3BFD00BEA33D /* SensorManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorManagerView.swift; sourceTree = ""; }; + 9822A1C72CDA9AD800CFFD13 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 9822A1CC2CDAA7A500CFFD13 /* FirebaseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseManager.swift; sourceTree = ""; }; + 9822A1D02CE3CD6000CFFD13 /* AuthManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthManager.swift; sourceTree = ""; }; + 9822A1D62CE3E8DE00CFFD13 /* MusicalCaneGame.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MusicalCaneGame.entitlements; sourceTree = ""; }; 98B8DBBA211340CA00BEB719 /* MediaToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaToolbox.framework; path = System/Library/Frameworks/MediaToolbox.framework; sourceTree = SDKROOT; }; 98C4ADDB2CED794F00CE98FA /* SensorDriver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorDriver.swift; sourceTree = ""; }; 98D44AE4211A2D8300E11840 /* BeaconViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BeaconViewController.swift; sourceTree = ""; }; @@ -97,9 +108,13 @@ buildActionMask = 2147483647; files = ( 9815A7B1211B3E3F00A2223F /* CoreLocation.framework in Frameworks */, + 9822A1D32CE3CDE900CFFD13 /* FirebaseAuth in Frameworks */, 98B8DBBB211340CA00BEB719 /* MediaToolbox.framework in Frameworks */, + 9822A1CB2CDAA4C900CFFD13 /* FirebaseAnalytics in Frameworks */, 98B8DB922112359A00BEB719 /* MobileCoreServices.framework in Frameworks */, 4959A5B52111F945006193E6 /* MediaPlayer.framework in Frameworks */, + 9822A1CF2CDAA8C000CFFD13 /* FirebaseFirestore in Frameworks */, + 9822A1D52CE3CE1C00CFFD13 /* FirebaseAuth in Frameworks */, AD6C6F05210267CB00E9D840 /* AVFoundation.framework in Frameworks */, AD6C6F03210267C600E9D840 /* CoreBluetooth.framework in Frameworks */, 57C85F49830BFA7051E7EE1A /* Pods_MusicalCaneGame.framework in Frameworks */, @@ -171,6 +186,9 @@ AD6C6EEE210267B700E9D840 /* MusicalCaneGame */ = { isa = PBXGroup; children = ( + 9822A1D62CE3E8DE00CFFD13 /* MusicalCaneGame.entitlements */, + 9822A1D02CE3CD6000CFFD13 /* AuthManager.swift */, + 9822A1CC2CDAA7A500CFFD13 /* FirebaseManager.swift */, 820EF29A239ED24C004A4BCD /* Sound Effects */, 820EF291239EBA7D004A4BCD /* Voice Notes */, 95BBF1FB216F8A0200DDA9DB /* ViewControllers */, @@ -196,6 +214,7 @@ 86591D8F224D049E0050816B /* SWRevealViewController.m */, 9582BE522167CC1D00F4209E /* MusicalCaneGame-Bridging-Header.h */, E5220F4D2256634E004AE171 /* DBInterface.swift */, + 9822A1C72CDA9AD800CFFD13 /* GoogleService-Info.plist */, ); path = MusicalCaneGame; sourceTree = ""; @@ -269,6 +288,9 @@ Base, ); mainGroup = AD6C6EE3210267B700E9D840; + packageReferences = ( + 9822A1C92CDAA4C900CFFD13 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + ); productRefGroup = AD6C6EED210267B700E9D840 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -285,6 +307,7 @@ files = ( 95BBF1FF216F8A4F00DDA9DB /* MusicSegmentViewController.xib in Resources */, AD6C6EFA210267B800E9D840 /* LaunchScreen.storyboard in Resources */, + 9822A1C82CDA9AD800CFFD13 /* GoogleService-Info.plist in Resources */, 820EF29F239ED24C004A4BCD /* StopRecording.aiff in Resources */, 981823A3211A3894006A28F7 /* White.jpg in Resources */, AD6C6EF7210267B800E9D840 /* Assets.xcassets in Resources */, @@ -344,6 +367,7 @@ buildActionMask = 2147483647; files = ( 820EF297239EBA7D004A4BCD /* AudioVisualizerView.swift in Sources */, + 9822A1D12CE3CD6700CFFD13 /* AuthManager.swift in Sources */, 98D44AE5211A2D8300E11840 /* BeaconViewController.swift in Sources */, 86591D90224D049E0050816B /* SWRevealViewController.m in Sources */, E5220F4E2256634E004AE171 /* DBInterface.swift in Sources */, @@ -357,6 +381,7 @@ 98C4ADDC2CED794F00CE98FA /* SensorDriver.swift in Sources */, 98A02ACD2CEE3BFE00BEA33D /* SensorManagerView.swift in Sources */, 95BBF1F22168232A00DDA9DB /* MusicViewController.swift in Sources */, + 9822A1CD2CDAA7AB00CFFD13 /* FirebaseManager.swift in Sources */, 951C05CA2178BE5500CD2998 /* SoundViewController.swift in Sources */, E5C038042268D0BD00373275 /* SensorManager.swift in Sources */, 9582BE572167CF0300F4209E /* MainViewController.swift in Sources */, @@ -511,6 +536,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = MusicalCaneGame/MusicalCaneGame.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 30; DEVELOPMENT_TEAM = 787TUDMR8Q; @@ -535,6 +561,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = MusicalCaneGame/MusicalCaneGame.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 30; DEVELOPMENT_TEAM = 787TUDMR8Q; @@ -574,6 +601,40 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 9822A1C92CDAA4C900CFFD13 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 11.4.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 9822A1CA2CDAA4C900CFFD13 /* FirebaseAnalytics */ = { + isa = XCSwiftPackageProductDependency; + package = 9822A1C92CDAA4C900CFFD13 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAnalytics; + }; + 9822A1CE2CDAA8C000CFFD13 /* FirebaseFirestore */ = { + isa = XCSwiftPackageProductDependency; + package = 9822A1C92CDAA4C900CFFD13 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseFirestore; + }; + 9822A1D22CE3CDE900CFFD13 /* FirebaseAuth */ = { + isa = XCSwiftPackageProductDependency; + package = 9822A1C92CDAA4C900CFFD13 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAuth; + }; + 9822A1D42CE3CE1C00CFFD13 /* FirebaseAuth */ = { + isa = XCSwiftPackageProductDependency; + package = 9822A1C92CDAA4C900CFFD13 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAuth; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = AD6C6EE4210267B700E9D840 /* Project object */; } diff --git a/MusicalCaneGame/AppDelegate.swift b/MusicalCaneGame/AppDelegate.swift index d3d70d8..67ece58 100755 --- a/MusicalCaneGame/AppDelegate.swift +++ b/MusicalCaneGame/AppDelegate.swift @@ -7,6 +7,7 @@ // import UIKit +import FirebaseCore @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -16,6 +17,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. + // Initialize firebase + FirebaseApp.configure() return true } diff --git a/MusicalCaneGame/AuthManager.swift b/MusicalCaneGame/AuthManager.swift new file mode 100644 index 0000000..1a57914 --- /dev/null +++ b/MusicalCaneGame/AuthManager.swift @@ -0,0 +1,153 @@ +// +// AuthManager.swift +// MusicalCaneGame +// +// Created by occamlab on 11/12/24. +// Copyright © 2024 occamlab. All rights reserved. +// + +import Foundation +import FirebaseCore +import FirebaseAuth +import CryptoKit +import AuthenticationServices +import SwiftUI + +class AuthManager: NSObject, ObservableObject, ASAuthorizationControllerDelegate { + public static var shared = AuthManager() + private var currentNonce: String? + + @Published var currentUID: String? + @Published var currentEmail: String? + + private let firebaseAuth = Auth.auth() + + private override init() { + currentUID = firebaseAuth.currentUser?.uid + currentEmail = firebaseAuth.currentUser?.email + super.init() + createAuthListener() + } + + private func createAuthListener() { + firebaseAuth.addStateDidChangeListener() { (auth, user) in + self.currentUID = user?.uid + print("currentUID \(self.currentUID ?? "nil")") + print("currentEmail \(user?.email)") + print("name \(user?.displayName)") + + // Ensure that a document exists for the current user within + // firebase + if self.currentUID != nil { + FirebaseManager.shared.checkOrAppendInstructorUID(instructorUID: self.currentUID!) + } + } + } + + private func randomNonceString(length: Int = 32) -> String { + precondition(length > 0) + var randomBytes = [UInt8](repeating: 0, count: length) + let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes) + if errorCode != errSecSuccess { + fatalError( + "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)" + ) + } + + let charset: [Character] = + Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._") + + let nonce = randomBytes.map { byte in + // Pick a random character from the set, wrapping around if needed. + charset[Int(byte) % charset.count] + } + + return String(nonce) + } + + private func sha256(_ input: String) -> String { + let inputData = Data(input.utf8) + let hashedData = SHA256.hash(data: inputData) + let hashString = hashedData.compactMap { + String(format: "%02x", $0) + }.joined() + + return hashString + } + + func startSignInWithAppleFlow() { + let nonce = randomNonceString() + currentNonce = nonce + let appleIDProvider = ASAuthorizationAppleIDProvider() + let request = appleIDProvider.createRequest() + request.requestedScopes = [.fullName, .email] + request.nonce = sha256(nonce) + + let authorizationController = ASAuthorizationController(authorizationRequests: [request]) + authorizationController.delegate = self + authorizationController.performRequests() + } + + /// A callback function that indicates authentication was successful. + /// - Parameters: + /// - controller: the controller that was used for authentication + /// - authorization: the authorization generated by the Apple authentication procedure + func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { + if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential { + guard let nonce = currentNonce else { + fatalError("Invalid state: A login callback was received, but no login request was sent.") + } + guard let appleIDToken = appleIDCredential.identityToken else { + print("Unable to fetch identity token") + return + } + guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else { + print("Unable to serialize token string from data: \(appleIDToken.debugDescription)") + return + } + // Initialize a Firebase credential, including the user's full name. + let credential = OAuthProvider.appleCredential(withIDToken: idTokenString, + rawNonce: nonce, + fullName: appleIDCredential.fullName) + // Sign in with Firebase. + Auth.auth().signIn(with: credential) { (authResult, error) in + if let error = error { + // Error. If error.code == .MissingOrInvalidNonce, make sure + // you're sending the SHA256-hashed nonce as a hex string with + // your request to Apple. + print(error.localizedDescription) + return + } + // User is signed in to Firebase with Apple. + // ... + } + } + } + + /// A callback function that is called when the authentication request failed + /// - Parameters: + /// - controller: the controller that requested the authentication with Apple + /// - error: the error that occurred + func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { + // Handle error. + print("Sign in with Apple errored: \(error)") + } +} + +/// A wrapper for the "Sign in with Apple" button for SwiftUI +struct SignInWithApple: UIViewRepresentable { + /// Creates the UIView as part of the `UIViewRepresentable` protocol + /// - Parameter context: the context for creating the UIView + /// - Returns: the UIView + func makeUIView(context: Context) -> ASAuthorizationAppleIDButton { + return ASAuthorizationAppleIDButton() + } + + /// + /// - Parameters: + /// - uiView: a handle to the ASAuthorizationAppleIDButton + /// - context: the context in which the update is occurring. + func updateUIView(_ uiView: ASAuthorizationAppleIDButton, context: Context) { + // no updates + } +} diff --git a/MusicalCaneGame/DBInterface.swift b/MusicalCaneGame/DBInterface.swift index 0e90e56..8db306b 100644 --- a/MusicalCaneGame/DBInterface.swift +++ b/MusicalCaneGame/DBInterface.swift @@ -8,6 +8,8 @@ For more information, documentation is here: https://github.com/stephencelis/SQLite.swift/blob/master/Documentation/Index.md */ +// use database, instead of storage in firebase + import Foundation import SQLite @@ -29,6 +31,9 @@ class DBInterface { /// user beacon mappings table let beaconMappings: Table = Table("BeaconMappings") + /// firebase manager + var fbManager: FirebaseManager = FirebaseManager.shared + /// column names let name: SQLite.Expression = Expression("name") let sweep_width: SQLite.Expression = Expression("sweep_width") @@ -52,7 +57,6 @@ class DBInterface { let beaconStatus: SQLite.Expression = Expression("beaconstatus") private init() { - let path = NSSearchPathForDirectoriesInDomains( .documentDirectory, .userDomainMask, true ).first! @@ -64,10 +68,9 @@ class DBInterface { print(error) return } - do { if (db != nil) { - //dropTable() + dropTable() // create the table if it doesn't exist try self.db!.run(self.users.create(ifNotExists: true) { t in t.column(self.name, primaryKey: true) @@ -79,12 +82,22 @@ class DBInterface { t.column(self.sweep_tolerance) t.column(self.beacons_enabled) t.column(self.wheelchair_user) - }) + }) // if there are no rows, add a default user let count = try self.db!.scalar(self.users.count) - print(count) if (count == 0) { - insertRow(u_name: "Default User", u_sweep_width: 20, u_cane_length: 40, u_music: "Select Music", u_beep_noise: "Begin Record", u_music_id: "", u_sweep_tolerance: 15, u_wheelchair_user: false) + print("count 0") + // If there are no users in the local db, check firebase to see if there are any records + fbManager.queryUsersForInstructor { [self]documentData in + print("document data: \(documentData)") + if documentData.isEmpty { + insertRow(u_name: "Default User", u_sweep_width: 20, u_cane_length: 40, u_music: "Select Music", u_beep_noise: "Begin Record", u_music_id: "", u_sweep_tolerance: 15, u_wheelchair_user: false) + } else { + for doc in documentData { + insertRow(u_name: doc["name"] as! String, u_sweep_width: doc["sweepWidth"] as! Double, u_cane_length: doc["caneLength"] as! Double, u_music: doc["music"] as! String, u_beep_noise: doc["beepNoise"] as! String, u_music_id: doc["musicId"] as! String, u_sweep_tolerance: doc["sweepTolerance"] as! Double, u_wheelchair_user: (doc["wheelchairUser"] != nil)) + } + } + } } try self.db!.run(self.beaconMappings.create(ifNotExists: true) { t in t.column(self.name) @@ -117,6 +130,9 @@ class DBInterface { print("insertion failed: \(error)") } } + + // Also upload the new entry to firebase + fbManager.addUser(name: u_name, sweep_width: u_sweep_width, cane_length: u_cane_length, music: u_music, beep_noise: u_beep_noise, music_id: u_music_id, sweep_tolerance: u_sweep_tolerance, wheelchair_user: u_wheelchair_user) } func getRow(u_name: String) -> Row?{ @@ -298,6 +314,7 @@ class DBInterface { func updateRow(u_name: String, u_sweep_width: Double, u_cane_length: Double, u_music: String, u_beep_noise: String, u_music_id: String, u_sweep_tolerance: Double, u_wheelchair_user: Bool) { // Update all values except the Beacon enabled flag + // TODO: also update the document on firebase do { try self.db!.run(self.users.filter(name == u_name) .update(sweep_width <- u_sweep_width, diff --git a/MusicalCaneGame/FirebaseManager.swift b/MusicalCaneGame/FirebaseManager.swift new file mode 100644 index 0000000..45e48a7 --- /dev/null +++ b/MusicalCaneGame/FirebaseManager.swift @@ -0,0 +1,79 @@ +// +// FirebaseManager.swift +// MusicalCaneGame +// +// Created by occamlab on 11/5/24. +// Copyright © 2024 occamlab. All rights reserved. +// + +import FirebaseFirestore + +class FirebaseManager: ObservableObject { + /// The singleton instance of this class + public static var shared = FirebaseManager() + + private let db: Firestore + + private var authManager: AuthManager = AuthManager.shared + + private init() { + db = Firestore.firestore() + } + + func checkOrAppendInstructorUID(instructorUID: String) { + let docRef = db.collection("instructors").document(instructorUID) + docRef.getDocument { (documentSnapshot, error) in + if let error = error { + print("Error getting document: \(error)") + return + } + + if let document = documentSnapshot, document.exists { + print("Document already exists") + } else { + // Document does not exist, create it with the provided data + let data: [String: Any] = ["firstName": "Ayush", "lastName": "Chakraborty", "email": "achakraborty@olin.edu"] + docRef.setData(data) { err in + if let err = err { + print("Error creating document: \(err)") + } else { + print("Document successfully created") + } + } + } + } + } + + func addUser(name: String, sweep_width: Double, cane_length: Double, music: String, beep_noise: String, music_id: String, sweep_tolerance: Double, wheelchair_user: Bool) { + _ = db.collection("users").addDocument(data: [ + "name": name, + "sweepWidth": sweep_width, + "caneLength": cane_length, + "music": music, + "beepNoise": beep_noise, + "musicId": music_id, + "sweepTolerance": sweep_tolerance, + "wheelchairUser": wheelchair_user, + "instructorUID": authManager.currentUID! + ]) + } + + func queryUsersForInstructor(completion: @escaping ([[String: Any]]) -> Void) { + var document_data: Array<[String: Any]> = Array() + db.collection("users").whereField("instructorUID", isEqualTo: authManager.currentUID!).getDocuments { (querySnapshot, error) in + if let error = error { + print("Error getting documents: \(error)") + completion([[:]]) + } else { + print("no error") + for document in querySnapshot!.documents { + print("appending") + print(document.data()) + print(document) + document_data.append(document.data()) + } + completion(document_data) + } + } + } +} diff --git a/MusicalCaneGame/MainViewController.swift b/MusicalCaneGame/MainViewController.swift index 544e8cb..46ed436 100644 --- a/MusicalCaneGame/MainViewController.swift +++ b/MusicalCaneGame/MainViewController.swift @@ -7,15 +7,21 @@ // import UIKit +import SwiftUI class MainViewController: UIViewController { + @IBOutlet weak var signInWithAppleContainer: UIView! @IBOutlet weak var menuButton: UIBarButtonItem! override func viewDidLoad() { super.viewDidLoad() sideMenu() // Do any additional setup after loading the view. + let signInView = UIHostingController(rootView: SignInWithApple().onTapGesture(perform: AuthManager.shared.startSignInWithAppleFlow)) + addChildViewController(signInView) + signInView.view.frame = signInWithAppleContainer.bounds + signInWithAppleContainer.addSubview(signInView.view) } override func didReceiveMemoryWarning() { diff --git a/MusicalCaneGame/MusicalCaneGame.entitlements b/MusicalCaneGame/MusicalCaneGame.entitlements new file mode 100644 index 0000000..a812db5 --- /dev/null +++ b/MusicalCaneGame/MusicalCaneGame.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.applesignin + + Default + + + diff --git a/Podfile.lock b/Podfile.lock index 61ce333..28cb1e8 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,11 +1,11 @@ PODS: - - Bolts/Tasks (1.8.4) - - FastCoding (3.2.2) + - Bolts-Swift (1.5.0) - FlexColorPicker (1.4.4) - MBProgressHUD (1.2.0) - - MetaWearPrivate (2.10.0): - - Bolts/Tasks (~> 1.8.4) - - FastCoding (~> 3.2.2) + - MetaWear (4.1.3): + - MetaWear/Core (= 4.1.3) + - MetaWear/Core (4.1.3): + - Bolts-Swift (~> 1) - PRTween (0.1.0) - SQLite.swift (0.11.6): - SQLite.swift/standard (= 0.11.6) @@ -15,41 +15,30 @@ PODS: DEPENDENCIES: - FlexColorPicker - MBProgressHUD - - MetaWearPrivate (from `https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS.git`, commit `1254b54`) + - MetaWear - PRTween (~> 0.1) - SQLite.swift (~> 0.11.5) - StaticDataTableViewController SPEC REPOS: trunk: - - Bolts - - FastCoding + - Bolts-Swift - FlexColorPicker - MBProgressHUD + - MetaWear - PRTween - SQLite.swift - StaticDataTableViewController -EXTERNAL SOURCES: - MetaWearPrivate: - :commit: 1254b54 - :git: https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS.git - -CHECKOUT OPTIONS: - MetaWearPrivate: - :commit: 1254b54 - :git: https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS.git - SPEC CHECKSUMS: - Bolts: 8a7995239dbe724f9cba2248b766d48b7ebdd322 - FastCoding: f7b1b75a2ccb0dd6ef9c928e46339e20252d98d3 + Bolts-Swift: afbbaf8c8186e7f769be4afa656949c14087ba44 FlexColorPicker: ce72e0a9e0870815a0beba419ac3e09913401624 MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406 - MetaWearPrivate: f9cb466d358f6a4a5639f3cce393ddaf37c4def5 + MetaWear: 172042a920e6853083f1fd94fb4f509016188586 PRTween: 6c58c7e32ebcf31e33e6a6e6bc727ebef3b668ef SQLite.swift: 46d890be8601964454bd3392527f863d1b802d45 StaticDataTableViewController: 0c5c4a47861446dd3cfd52530ae801ec7662ce26 -PODFILE CHECKSUM: 010e7e706eb37c9ef154fb2e9dd3e9eecd5cba8f +PODFILE CHECKSUM: 16aec52e84a0b81c82c2e4b53a90b7147cf33fb1 COCOAPODS: 1.15.2 diff --git a/Pods/Bolts-Swift/LICENSE b/Pods/Bolts-Swift/LICENSE new file mode 100644 index 0000000..4cdb491 --- /dev/null +++ b/Pods/Bolts-Swift/LICENSE @@ -0,0 +1,30 @@ +BSD License + +For Bolts-Swift software + +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Pods/Bolts-Swift/README.md b/Pods/Bolts-Swift/README.md new file mode 100644 index 0000000..9f3a1f0 --- /dev/null +++ b/Pods/Bolts-Swift/README.md @@ -0,0 +1,198 @@ +# Bolts in Swift + +![Platforms][platforms-svg] +![Swift Version][swift-version-svg] + +[![Podspec][podspec-svg]][podspec-link] +[![Carthage compatible][carthage-svg]](carthage-link) +[![Swift Package Manager compatible](swiftpm-svg)](swiftpm-link) +[![License][license-svg]][license-link] + +[![Build Status][build-status-svg]][build-status-link] +[![Coverage Status][coverage-status-svg]][coverage-status-link] + +Bolts is a collection of low-level libraries designed to make developing mobile apps easier. Bolts was designed by Parse and Facebook for our own internal use, and we have decided to open source these libraries to make them available to others. + +## Tasks + +Bolts Tasks is a complete implementation of futures/promises for iOS/OS X/watchOS/tvOS and any platform that supports Swift. +A task represents the result of an asynchronous operation, which typically would be returned from a function. +In addition to being able to have different states `completed`/`faulted`/`cancelled` they provide these benefits: + +- `Tasks` consume fewer system resources, since they don't occupy a thread while waiting on other `Tasks`. +- `Tasks` could be performed/chained in a row which will not create nested "pyramid" code as you would get when using only callbacks. +- `Tasks` are fully composable, allowing you to perform branching, parallelism, and complex error handling, without the spaghetti code of having many named callbacks. +- `Tasks` allow you to arrange code in the order that it executes, rather than having to split your logic across scattered callback functions. +- `Tasks` don't depend on any particular threading model. So you can use concepts like operation queues/dispatch queues or even thread executors. +- `Tasks` could be used synchronously or asynchronously, providing the same benefit of different results of any function/operation. + +## Getting Started + +- **[CocoaPods](https://cocoapods.org)** + + Add the following line to your Podfile: + + ```ruby + pod 'Bolts-Swift' + ``` + + Run `pod install`, and you should now have the latest parse release. + +- **[Carthage](https://github.com/carthage/carthage)** + + Add the following line to your Cartfile: + + ``` + github "BoltsFramework/Bolts-Swift" + ``` + + Run `carthage update`, and you should now have the latest version of Bolts in your Carthage folder. + +- **Using Bolts as a sub-project** + + You can also include Bolts as a subproject inside of your application if you'd prefer, although we do not recommend this, as it will increase your indexing time significantly. To do so, just drag and drop the `BoltsSwift.xcodeproj` file into your workspace. + +- **Import Bolts** + + Now that you have the framework linked to your application - add the folowing line in every `.swift` that you want to use Bolts from: + + ``` + import BoltsSwift + ``` + +## Chaining Tasks + +There are special methods you can call on a task which accept a closure argument and will return the task object. Because they return tasks it means you can keep calling these methods – also known as _chaining_ – to perform logic in stages. This is a powerful approach that makes your code read as a sequence of steps, while harnessing the power of asynchronous execution. Here are 3 key functions you should know: + +1. Use `continueWith` to inspect the task after it has ran and perform more operations with the result +1. Use `continueWithTask` to add more work based on the result of the previous task +1. Use `continueOnSuccessWith` to perform logic only when task executed without errors + +For full list of available methods please see source code at **[Task+ContinueWith.swift][continueWith-source]** + +### continueWith + +Every `Task` has a function named `continueWith`, which takes a continuation closure. A continuation will be executed when the task is complete. You can the inspect the task to check if it was successful and to get its result. + +```swift +save(object).continueWith { task in + if task.cancelled { + // Save was cancelled + } else if task.faulted { + // Save failed + } else { + // Object was successfully saved + let result = task.result + } +} +``` + +### continueOnSuccessWith + +In many cases, you only want to do more work if the previous task was successful, and propagate any error or cancellation to be dealt with later. To do this, use `continueOnSuccessWith` function: + +```swift +save(object).continueOnSuccessWith { result in + // Closure receives the result of a succesfully performed task + // If result is invalid throw an error which will mark task as faulted +} +``` + +Underneath, `continueOnSuccessWith` is calling `continueOnSuccessWithTask` method which is more powerful and useful for situations where you want to spawn additional work. + +### continueOnSuccessWithTask + +As you saw above, if you return an object from `continueWith` function – it will become a result the Task. But what if there is more work to do? If you want to call into more tasks and return their results instead – you can use `continueWithTask`. This gives you an ability to chain more asynchronous work together. + +In the following example we want to fetch a user profile, then fetch a profile image, and if any of these operations failed - we still want to display an placeholder image: + +```swift +fetchProfile(user).continueOnSuccessWithTask { task in + return fetchProfileImage(task.result); +}.continueWith { task in + if let image = task.result { + return image + } + return ProfileImagePlaceholder() +} +``` + +## Creating Tasks + +To create a task - you would need a `TaskCompletionSource`, which is a consumer end of any `Task`, which gives you an ability to control whether the task is completed/faulted or cancelled. +After you create a `TaskCompletionSource`, you need to call `setResult()`/`setError()`/`cancel()` to trigger its continuations and change its state. + +```swift +func fetch(object: PFObject) -> Task { + let taskCompletionSource = TaskCompletionSource() + object.fetchInBackgroundWithBlock() { (object: PFObject?, error: NSError?) in + if let error = error { + taskCompletionSource.setError(error) + } else if let object = object { + taskCompletionSource.setResult(object) + } else { + taskCompletionSource.cancel() + } + } + return taskCompletionSource.task +} +``` + +## Tasks in Parallel + +You can also perform several tasks in parallel and chain the result of all of them using `whenAll()` function. + +```swift +let query = PFQuery(className: "Comments") +find(query).continueWithTask { task in + var tasks: [Task] = [] + task.result?.forEach { comment in + tasks.append(self.deleteComment(comment)) + } + return Task.whenAll(tasks) +}.continueOnSuccessWith { task in + // All comments were deleted +} +``` + +## Task Executors + +Both `continueWith()` and `continueWithTask()` functions accept an optional executor parameter. It allows you to control how the continuation closure is executed. +The default executor will dispatch to global dispatch queue, but you can provide your own executor to schedule work in a specific way. +For example, if you want to continue with work on the main thread: + +```swift +fetch(object).continueWith(Executor.mainThread) { task in + // This closure will be executor on the main application's thread +} +``` + +## How Do I Contribute? + +We want to make contributing to this project as easy and transparent as possible. Please refer to the [Contribution Guidelines][contributing]. + + [releases]: https://github.com/BoltsFramework/Bolts-Swift/releases + [contributing]: https://github.com/BoltsFramework/Bolts-Swift/blob/master/CONTRIBUTING.md + + [build-status-svg]: https://img.shields.io/travis/BoltsFramework/Bolts-Swift/master.svg + [build-status-link]: https://travis-ci.org/BoltsFramework/Bolts-Swift/branches + + [coverage-status-svg]: https://img.shields.io/codecov/c/github/BoltsFramework/Bolts-Swift/master.svg + [coverage-status-link]: https://codecov.io/github/BoltsFramework/Bolts-Swift?branch=master + + [license-svg]: https://img.shields.io/badge/license-BSD-lightgrey.svg + [license-link]: https://github.com/BoltsFramework/Bolts-Swift/blob/master/LICENSE + + [podspec-svg]: https://img.shields.io/cocoapods/v/Bolts-Swift.svg + [podspec-link]: https://cocoapods.org/pods/Bolts-Swift + + [carthage-svg]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat + [carthage-link]: https://github.com/carthage/carthage + + [swiftpm-svg]: https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg?style=flat + [swiftpm-link]: https://github.com/apple/swift-package-manager + + [platforms-svg]: http://img.shields.io/cocoapods/p/Bolts-Swift.svg?style=flat + [swift-version-svg]: https://img.shields.io/badge/Swift-5-orange.svg + + [continueWith-source]: https://github.com/BoltsFramework/Bolts-Swift/blob/master/Sources/BoltsSwift/Task%2BContinueWith.swift diff --git a/Pods/Bolts-Swift/Sources/BoltsSwift/Errors.swift b/Pods/Bolts-Swift/Sources/BoltsSwift/Errors.swift new file mode 100644 index 0000000..ec3db5b --- /dev/null +++ b/Pods/Bolts-Swift/Sources/BoltsSwift/Errors.swift @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +/** + An error type that contains one or more underlying errors. + */ +public struct AggregateError: Error { + /// An array of errors that are aggregated into this one. + public let errors: [Error] + + init(errors: [Error]) { + self.errors = errors + } +} + +/** + An error type that indicates that the task was cancelled. + + Return or throw this from a continuation closure to propagate to the `task.cancelled` property. + */ +public struct CancelledError: Error { + /** + Initializes a Cancelled Error. + */ + public init() { } +} diff --git a/Pods/Bolts-Swift/Sources/BoltsSwift/Executor.swift b/Pods/Bolts-Swift/Sources/BoltsSwift/Executor.swift new file mode 100644 index 0000000..34edc43 --- /dev/null +++ b/Pods/Bolts-Swift/Sources/BoltsSwift/Executor.swift @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +/// `Executor` is an `enum`, that defines different strategies for calling closures. +public enum Executor { + + /** + Calls closures immediately unless the call stack gets too deep, + in which case it dispatches the closure in the default priority queue. + */ + case `default` + + /** + Calls closures immediately. + Tasks continuations will be run in the thread of the previous task. + */ + case immediate + + /** + Calls closures on the main thread. + Will execute synchronously if already on the main thread, otherwise - will execute asynchronously. + */ + case mainThread + + /** + Dispatches closures on a GCD queue. + */ + case queue(DispatchQueue) + + /** + Adds closures to an operation queue. + */ + case operationQueue(Foundation.OperationQueue) + + /** + Passes closures to an executing closure. + */ + case closure((() -> Void) -> Void) + + /** + Passes escaping closures to an executing closure. + */ + case escapingClosure((@escaping () -> Void) -> Void) + + /** + Executes the given closure using the corresponding strategy. + + - parameter closure: The closure to execute. + */ + public func execute(_ closure: @escaping () -> Void) { + switch self { + case .default: + struct Static { + static let taskDepthKey = "com.bolts.TaskDepthKey" + static let maxTaskDepth = 20 + } + + let localThreadDictionary = Thread.current.threadDictionary + + var previousDepth: Int + if let depth = localThreadDictionary[Static.taskDepthKey] as? Int { + previousDepth = depth + } else { + previousDepth = 0 + } + + if previousDepth > Static.maxTaskDepth { + DispatchQueue.global(qos: .default).async(execute: closure) + } else { + localThreadDictionary[Static.taskDepthKey] = previousDepth + 1 + closure() + localThreadDictionary[Static.taskDepthKey] = previousDepth + } + case .immediate: + closure() + case .mainThread: + if Thread.isMainThread { + closure() + } else { + DispatchQueue.main.async(execute: closure) + } + case .queue(let queue): + queue.async(execute: closure) + case .operationQueue(let operationQueue): + operationQueue.addOperation(closure) + case .closure(let executingClosure): + executingClosure(closure) + case .escapingClosure(let executingEscapingClosure): + executingEscapingClosure(closure) + } + } +} + +extension Executor : CustomStringConvertible, CustomDebugStringConvertible { + /// A textual representation of `self`. + public var description: String { + switch self { + case .default: + return "Default Executor" + case .immediate: + return "Immediate Executor" + case .mainThread: + return "MainThread Executor" + case .queue: + return "Executor with dispatch_queue" + case .operationQueue: + return "Executor with NSOperationQueue" + case .closure: + return "Executor with custom closure" + case .escapingClosure: + return "Executor with custom escaping closure" + } + } + + /// A textual representation of `self`, suitable for debugging. + public var debugDescription: String { + switch self { + case .queue(let object): + return "\(description): \(object)" + case .operationQueue(let queue): + return "\(description): \(queue)" + case .closure(let closure): + return "\(description): \(String(describing: closure))" + case .escapingClosure(let closure): + return "\(description): \(String(describing: closure))" + default: + return description + } + } +} diff --git a/Pods/Bolts-Swift/Sources/BoltsSwift/Task+ContinueWith.swift b/Pods/Bolts-Swift/Sources/BoltsSwift/Task+ContinueWith.swift new file mode 100644 index 0000000..8fbc2b7 --- /dev/null +++ b/Pods/Bolts-Swift/Sources/BoltsSwift/Task+ContinueWith.swift @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2016, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +//-------------------------------------- +// MARK: - ContinueWith +//-------------------------------------- + +extension Task { + /** + Internal continueWithTask. This is the method that all other continuations must go through. + + - parameter executor: The executor to invoke the closure on. + - parameter options: The options to run the closure with + - parameter continuation: The closure to execute. + + - returns: The task resulting from the continuation + */ + fileprivate func continueWithTask(_ executor: Executor, + options: TaskContinuationOptions, + continuation: @escaping ((Task) throws -> Task) + ) -> Task { + let taskCompletionSource = TaskCompletionSource() + let wrapperContinuation = { + switch self.state { + case .success where options.contains(.RunOnSuccess): fallthrough + case .error where options.contains(.RunOnError): fallthrough + case .cancelled where options.contains(.RunOnCancelled): + executor.execute { + let wrappedState = TaskState>.fromClosure { + try continuation(self) + } + switch wrappedState { + case .success(let nextTask): + switch nextTask.state { + case .pending: + nextTask.continueWith { nextTask in + taskCompletionSource.setState(nextTask.state) + } + default: + taskCompletionSource.setState(nextTask.state) + } + case .error(let error): + taskCompletionSource.set(error: error) + case .cancelled: + taskCompletionSource.cancel() + default: abort() // This should never happen. + } + } + + case .success(let result as S): + // This is for continueOnErrorWith - the type of the result doesn't change, so we can pass it through + taskCompletionSource.set(result: result) + + case .error(let error): + taskCompletionSource.set(error: error) + + case .cancelled: + taskCompletionSource.cancel() + + default: + fatalError("Task was in an invalid state \(self.state)") + } + } + appendOrRunContinuation(wrapperContinuation) + return taskCompletionSource.task + } + + /** + Enqueues a given closure to be run once this task is complete. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter continuation: The closure that returns the result of the task. + + - returns: A task that will be completed with a result from a given closure. + */ + @discardableResult + public func continueWith(_ executor: Executor = .default, continuation: @escaping ((Task) throws -> S)) -> Task { + return continueWithTask(executor) { task in + let state = TaskState.fromClosure({ + try continuation(task) + }) + return Task(state: state) + } + } + + /** + Enqueues a given closure to be run once this task is complete. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter continuation: The closure that returns a task to chain on. + + - returns: A task that will be completed when a task returned from a closure is completed. + */ + @discardableResult + public func continueWithTask(_ executor: Executor = .default, continuation: @escaping ((Task) throws -> Task)) -> Task { + return continueWithTask(executor, options: .RunAlways, continuation: continuation) + } +} + +//-------------------------------------- +// MARK: - ContinueOnSuccessWith +//-------------------------------------- + +extension Task { + /** + Enqueues a given closure to be run once this task completes with success (has intended result). + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter continuation: The closure that returns a task to chain on. + + - returns: A task that will be completed when a task returned from a closure is completed. + */ + @discardableResult + public func continueOnSuccessWith(_ executor: Executor = .default, + continuation: @escaping ((TResult) throws -> S)) -> Task { + return continueOnSuccessWithTask(executor) { taskResult in + let state = TaskState.fromClosure({ + try continuation(taskResult) + }) + return Task(state: state) + } + } + + /** + Enqueues a given closure to be run once this task completes with success (has intended result). + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter continuation: The closure that returns a task to chain on. + + - returns: A task that will be completed when a task returned from a closure is completed. + */ + @discardableResult + public func continueOnSuccessWithTask(_ executor: Executor = .default, + continuation: @escaping ((TResult) throws -> Task)) -> Task { + return continueWithTask(executor, options: .RunOnSuccess) { task in + return try continuation(task.result!) + } + } +} + +//-------------------------------------- +// MARK: - ContinueOnErrorWith +//-------------------------------------- + +extension Task { + /** + Enqueues a given closure to be run once this task completes with error. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter continuation: The closure that returns a task to chain on. + + - returns: A task that will be completed when a task returned from a closure is completed. + */ + @discardableResult + public func continueOnErrorWith(_ executor: Executor = .default, continuation: @escaping ((E) throws -> TResult)) -> Task { + return continueOnErrorWithTask(executor) { (error: E) in + let state = TaskState.fromClosure({ + try continuation(error) + }) + return Task(state: state) + } + } + + /** + Enqueues a given closure to be run once this task completes with error. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter continuation: The closure that returns a task to chain on. + + - returns: A task that will be completed when a task returned from a closure is completed. + */ + @discardableResult + public func continueOnErrorWith(_ executor: Executor = .default, continuation: @escaping ((Error) throws -> TResult)) -> Task { + return continueOnErrorWithTask(executor) { (error: Error) in + let state = TaskState.fromClosure({ + try continuation(error) + }) + return Task(state: state) + } + } + + /** + Enqueues a given closure to be run once this task completes with error. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter continuation: The closure that returns a task to chain on. + + - returns: A task that will be completed when a task returned from a closure is completed. + */ + @discardableResult + public func continueOnErrorWithTask(_ executor: Executor = .default, continuation: @escaping ((E) throws -> Task)) -> Task { + return continueOnErrorWithTask(executor) { (error: Error) in + if let error = error as? E { + return try continuation(error) + } + return Task(state: .error(error)) + } + } + + /** + Enqueues a given closure to be run once this task completes with error. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter continuation: The closure that returns a task to chain on. + + - returns: A task that will be completed when a task returned from a closure is completed. + */ + @discardableResult + public func continueOnErrorWithTask(_ executor: Executor = .default, continuation: @escaping ((Error) throws -> Task)) -> Task { + return continueWithTask(executor, options: .RunOnError) { task in + return try continuation(task.error!) + } + } +} diff --git a/Pods/Bolts-Swift/Sources/BoltsSwift/Task+Delay.swift b/Pods/Bolts-Swift/Sources/BoltsSwift/Task+Delay.swift new file mode 100644 index 0000000..1c8feb6 --- /dev/null +++ b/Pods/Bolts-Swift/Sources/BoltsSwift/Task+Delay.swift @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +//-------------------------------------- +// MARK: - Task with Delay +//-------------------------------------- + +extension Task { + /** + Creates a task that will complete after the given delay. + + - parameter delay: The delay for the task to completes. + + - returns: A task that will complete after the given delay. + */ + public class func withDelay(_ delay: TimeInterval) -> Task { + let taskCompletionSource = TaskCompletionSource() + let time = DispatchTime.now() + delay + DispatchQueue.global(qos: .default).asyncAfter(deadline: time) { + taskCompletionSource.trySet(result: ()) + } + return taskCompletionSource.task + } +} diff --git a/Pods/Bolts-Swift/Sources/BoltsSwift/Task+WhenAll.swift b/Pods/Bolts-Swift/Sources/BoltsSwift/Task+WhenAll.swift new file mode 100644 index 0000000..84f1bdf --- /dev/null +++ b/Pods/Bolts-Swift/Sources/BoltsSwift/Task+WhenAll.swift @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +//-------------------------------------- +// MARK: - WhenAll +//-------------------------------------- + +extension Task { + + /** + Creates a task that will be completed after all of the input tasks have completed. + + - parameter tasks: Array tasks to wait on for completion. + + - returns: A new task that will complete after all `tasks` are completed. + */ + public class func whenAll(_ tasks: [Task]) -> Task { + if tasks.isEmpty { + return Task.emptyTask() + } + + var tasksCount: Int32 = Int32(tasks.count) + var cancelledCount: Int32 = 0 + var errorCount: Int32 = 0 + + let tcs = TaskCompletionSource() + tasks.forEach { + $0.continueWith { task -> Void in + if task.cancelled { + OSAtomicIncrement32(&cancelledCount) + } else if task.faulted { + OSAtomicIncrement32(&errorCount) + } + + if OSAtomicDecrement32(&tasksCount) == 0 { + if cancelledCount > 0 { + tcs.cancel() + } else if errorCount > 0 { + #if swift(>=4.1) + tcs.set(error: AggregateError(errors: tasks.compactMap({ $0.error }))) + #else + tcs.set(error: AggregateError(errors: tasks.flatMap({ $0.error }))) + #endif + } else { + tcs.set(result: ()) + } + } + } + } + return tcs.task + } + + /** + Creates a task that will be completed after all of the input tasks have completed. + + - parameter tasks: Zero or more tasks to wait on for completion. + + - returns: A new task that will complete after all `tasks` are completed. + */ + public class func whenAll(_ tasks: Task...) -> Task { + return whenAll(tasks) + } + + /** + Creates a task that will be completed after all of the input tasks have completed. + + - parameter tasks: Array of tasks to wait on for completion. + + - returns: A new task that will complete after all `tasks` are completed. + The result of the task is going an array of results of all tasks in the same order as they were provided. + */ + public class func whenAllResult(_ tasks: [Task]) -> Task<[TResult]> { + return whenAll(tasks).continueOnSuccessWithTask { task -> Task<[TResult]> in + let results: [TResult] = tasks.map { task in + guard let result = task.result else { + // This should never happen. + // If the task succeeded - there is no way result is `nil`, even in case TResult is optional, + // because `task.result` would have a type of `Result??`, and we unwrap only one optional here. + // If a task was cancelled, we should have never have gotten past 'continueOnSuccess'. + // If a task errored, we should have returned a 'AggregateError' and never gotten past 'continueOnSuccess'. + // If a task was pending, then something went horribly wrong. + fatalError("Task is in unknown state \(task.state).") + } + return result + } + return Task<[TResult]>(results) + } + } + + /** + Creates a task that will be completed after all of the input tasks have completed. + + - parameter tasks: Zero or more tasks to wait on for completion. + + - returns: A new task that will complete after all `tasks` are completed. + The result of the task is going an array of results of all tasks in the same order as they were provided. + */ + public class func whenAllResult(_ tasks: Task...) -> Task<[TResult]> { + return whenAllResult(tasks) + } +} diff --git a/Pods/Bolts-Swift/Sources/BoltsSwift/Task+WhenAny.swift b/Pods/Bolts-Swift/Sources/BoltsSwift/Task+WhenAny.swift new file mode 100644 index 0000000..90abced --- /dev/null +++ b/Pods/Bolts-Swift/Sources/BoltsSwift/Task+WhenAny.swift @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +//-------------------------------------- +// MARK: - WhenAny +//-------------------------------------- + +extension Task { + + /** + Creates a task that will complete when any of the input tasks have completed. + + The returned task will complete when any of the supplied tasks have completed. + This is true even if the first task to complete ended in the canceled or faulted state. + + - parameter tasks: Array of tasks to wait on for completion. + + - returns: A new task that will complete when any of the `tasks` are completed. + */ + public class func whenAny(_ tasks: [Task]) -> Task { + if tasks.isEmpty { + return Task.emptyTask() + } + let taskCompletionSource = TaskCompletionSource() + for task in tasks { + // Do not continue anything if we completed the task, because we fulfilled our job here. + if taskCompletionSource.task.completed { + break + } + task.continueWith { task in + taskCompletionSource.trySet(result: ()) + } + } + return taskCompletionSource.task + } + + /** + Creates a task that will complete when any of the input tasks have completed. + + The returned task will complete when any of the supplied tasks have completed. + This is true even if the first task to complete ended in the canceled or faulted state. + + - parameter tasks: Zeror or more tasks to wait on for completion. + + - returns: A new task that will complete when any of the `tasks` are completed. + */ + public class func whenAny(_ tasks: Task...) -> Task { + return whenAny(tasks) + } +} diff --git a/Pods/Bolts-Swift/Sources/BoltsSwift/Task.swift b/Pods/Bolts-Swift/Sources/BoltsSwift/Task.swift new file mode 100644 index 0000000..2c5a4b8 --- /dev/null +++ b/Pods/Bolts-Swift/Sources/BoltsSwift/Task.swift @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2016, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +enum TaskState { + case pending + case success(TResult) + case error(Error) + case cancelled + + static func fromClosure(_ closure: () throws -> TResult) -> TaskState { + do { + return .success(try closure()) + } catch is CancelledError { + return .cancelled + } catch { + return .error(error) + } + } +} + +struct TaskContinuationOptions: OptionSet { + let rawValue: Int + init(rawValue: Int) { + self.rawValue = rawValue + } + + static let RunOnSuccess = TaskContinuationOptions(rawValue: 1 << 0) + static let RunOnError = TaskContinuationOptions(rawValue: 1 << 1) + static let RunOnCancelled = TaskContinuationOptions(rawValue: 1 << 2) + + static let RunAlways: TaskContinuationOptions = [ .RunOnSuccess, .RunOnError, .RunOnCancelled ] +} + +//-------------------------------------- +// MARK: - Task +//-------------------------------------- + +/// +/// The consumer view of a Task. +/// Task has methods to inspect the state of the task, and to add continuations to be run once the task is complete. +/// +public final class Task { + public typealias Continuation = () -> Void + + fileprivate let synchronizationQueue = DispatchQueue(label: "com.bolts.task", attributes: DispatchQueue.Attributes.concurrent) + fileprivate var _completedCondition: NSCondition? + + fileprivate var _state: TaskState = .pending + fileprivate var _continuations: [Continuation] = Array() + + // MARK: Initializers + + init() {} + + init(state: TaskState) { + _state = state + } + + /** + Creates a task that is already completed with the given result. + + - parameter result: The task result. + */ + public init(_ result: TResult) { + _state = .success(result) + } + + /** + Initializes a task that is already completed with the given error. + + - parameter error: The task error. + */ + public init(error: Error) { + _state = .error(error) + } + + /** + Creates a cancelled task. + + - returns: A cancelled task. + */ + public class func cancelledTask() -> Self { + // Swift prevents this method from being called `cancelled` due to the `cancelled` instance var. This is most likely a bug. + return self.init(state: .cancelled) + } + + class func emptyTask() -> Task { + return Task(state: .success(())) + } + + // MARK: Execute + + /** + Creates a task that will complete with the result of the given closure. + + - note: The closure cannot make the returned task to fail. Use the other `execute` overload for this. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter closure: The closure that returns the result of the task. + The returned task will complete when the closure completes. + */ + public convenience init(_ executor: Executor = .default, closure: @escaping (() throws -> TResult)) { + self.init(state: .pending) + executor.execute { + self.trySet(state: TaskState.fromClosure(closure)) + } + } + + /** + Creates a task that will continue with the task returned by the given closure. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter closure: The closure that returns the continuation task. + The returned task will complete when the continuation task completes. + + - returns: A task that will continue with the task returned by the given closure. + */ + public class func execute(_ executor: Executor = .default, closure: @escaping (() throws -> TResult)) -> Task { + return Task(executor, closure: closure) + } + + /** + Creates a task that will continue with the task returned by the given closure. + + - parameter executor: Determines how the the closure is called. The default is to call the closure immediately. + - parameter closure: The closure that returns the continuation task. + The returned task will complete when the continuation task completes. + + - returns: A task that will continue with the task returned by the given closure. + */ + public class func executeWithTask(_ executor: Executor = .default, closure: @escaping (() throws -> Task)) -> Task { + return emptyTask().continueWithTask(executor) { _ in + return try closure() + } + } + + // MARK: State Accessors + + /// Whether this task is completed. A completed task can also be faulted or cancelled. + public var completed: Bool { + switch state { + case .pending: + return false + default: + return true + } + } + + /// Whether this task has completed due to an error or exception. A `faulted` task is also completed. + public var faulted: Bool { + switch state { + case .error: + return true + default: + return false + } + } + + /// Whether this task has been cancelled. A `cancelled` task is also completed. + public var cancelled: Bool { + switch state { + case .cancelled: + return true + default: + return false + } + } + + /// The result of a successful task. Won't be set until the task completes with a `result`. + public var result: TResult? { + switch state { + case .success(let result): + return result + default: + break + } + return nil + } + + /// The error of a errored task. Won't be set until the task completes with `error`. + public var error: Error? { + switch state { + case .error(let error): + return error + default: + break + } + return nil + } + + /** + Waits until this operation is completed. + + This method is inefficient and consumes a thread resource while it's running. + It should be avoided. This method logs a warning message if it is used on the main thread. + */ + public func waitUntilCompleted() { + if Thread.isMainThread { + debugPrint("Warning: A long-running operation is being executed on the main thread waiting on \(self).") + } + + var conditon: NSCondition? + synchronizationQueue.sync(flags: .barrier, execute: { + if case .pending = self._state { + conditon = self._completedCondition ?? NSCondition() + self._completedCondition = conditon + } + }) + + guard let condition = conditon else { + // Task should have been completed + precondition(completed) + return + } + + condition.lock() + while !completed { + condition.wait() + } + condition.unlock() + + synchronizationQueue.sync(flags: .barrier, execute: { + self._completedCondition = nil + }) + } + + // MARK: State Change + + @discardableResult + func trySet(state: TaskState) -> Bool { + var stateChanged = false + + var continuations: [Continuation]? + var completedCondition: NSCondition? + synchronizationQueue.sync(flags: .barrier, execute: { + switch self._state { + case .pending: + stateChanged = true + self._state = state + continuations = self._continuations + completedCondition = self._completedCondition + self._continuations.removeAll() + default: + break + } + }) + if stateChanged { + completedCondition?.lock() + completedCondition?.broadcast() + completedCondition?.unlock() + + for continuation in continuations! { + continuation() + } + } + + return stateChanged + } + + // MARK: Internal + + func appendOrRunContinuation(_ continuation: @escaping Continuation) { + var runContinuation = false + synchronizationQueue.sync(flags: .barrier, execute: { + switch self._state { + case .pending: + self._continuations.append(continuation) + default: + runContinuation = true + } + }) + if runContinuation { + continuation() + } + } + + var state: TaskState { + var value: TaskState? + synchronizationQueue.sync { + value = self._state + } + return value! + } +} + +//-------------------------------------- +// MARK: - Description +//-------------------------------------- + +extension Task: CustomStringConvertible, CustomDebugStringConvertible { + /// A textual representation of `self`. + public var description: String { + return "Task: \(self.state)" + } + + /// A textual representation of `self`, suitable for debugging. + public var debugDescription: String { + return "Task: \(self.state)" + } +} diff --git a/Pods/Bolts-Swift/Sources/BoltsSwift/TaskCompletionSource.swift b/Pods/Bolts-Swift/Sources/BoltsSwift/TaskCompletionSource.swift new file mode 100644 index 0000000..e7ecf59 --- /dev/null +++ b/Pods/Bolts-Swift/Sources/BoltsSwift/TaskCompletionSource.swift @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import Foundation + +/// A `TaskCompletionSource` represents the producer side of a `Task`, +/// providing access to the consumer side through the `task` property. +/// As a producer, it can complete the underlying task by either by setting its result, error or cancelling it. +/// +/// For example, this is how you could use a task completion source +/// to provide a task that asynchronously reads data from disk: +/// +/// func dataFromPath(path: String) -> Task { +/// let tcs = TaskCompletionSource() +/// DispatchQueue.global(qos: .default).async { +/// if let data = NSData(contentsOfFile: path) { +/// tcs.set(result: data) +/// } else { +/// tcs.set(error: NSError(domain: "com.example", code: 0, userInfo: nil)) +/// } +/// } +/// return tcs.task +/// } +public class TaskCompletionSource { + + /// The underlying task. + public let task = Task() + + /// Creates a task completion source with a pending task. + public init() {} + + //-------------------------------------- + // MARK: - Change Task State + //-------------------------------------- + + /** + Completes the task with the given result. + + Throws an exception if the task is already completed. + + - parameter result: The task result. + */ + public func set(result: TResult) { + guard task.trySet(state: .success(result)) else { + preconditionFailure("Can not set the result on a completed task.") + } + } + + /** + Completes the task with the given error. + + Throws an exception if the task is already completed. + + - parameter error: The task error. + */ + public func set(error: Error) { + guard task.trySet(state: .error(error)) else { + preconditionFailure("Can not set error on a completed task.") + } + } + + /** + Cancels the task. + + Throws an exception if the task is already completed. + */ + public func cancel() { + guard task.trySet(state: .cancelled) else { + preconditionFailure("Can not cancel a completed task.") + } + } + + /** + Tries to complete the task with the given result. + + - parameter result: The task result. + - returns: `true` if the result was set, `false` otherwise. + */ + @discardableResult + public func trySet(result: TResult) -> Bool { + return task.trySet(state: .success(result)) + } + + /** + Tries to completes the task with the given error. + + - parameter error: The task error. + - returns: `true` if the error was set, `false` otherwise. + */ + @discardableResult + public func trySet(error: Error) -> Bool { + return task.trySet(state: .error(error)) + } + + /** + Cancels the task. + + - returns: `true` if the task was completed, `false` otherwise. + */ + @discardableResult + public func tryCancel() -> Bool { + return task.trySet(state: .cancelled) + } + + //-------------------------------------- + // MARK: - Change Task State (internal) + //-------------------------------------- + + func setState(_ state: TaskState) { + guard task.trySet(state: state) else { + preconditionFailure("Can not complete a completed task.") + } + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerController.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerController.swift new file mode 100644 index 0000000..0e8893c --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerController.swift @@ -0,0 +1,205 @@ +// +// ColorPicker.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Principal class and the controller of FlexColorPicker (not to be confused with view controllers). Synchronizes selected color of separate color controls so they can cooperate as one system. Also responsible for notifying client code via delegate. +/// +/// This can also be used from interface builder (e.g. a storyboard) as a class of custom object and the controls can be added to the controler by using Connection Inspector's outlets. +/// +/// **See also:** +/// [CustomColorPickerViewController](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/CustomColorPickerViewController.swift), [DefaultColorPickerViewController](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/DefaultColorPickerViewController.swift) +open class ColorPickerController: NSObject, ColorPickerControllerProtocol { //subclassing NSObject is required to use this class as object in interface builder + /// HSB representation of currently selected color. + public private(set) var selectedHSBColor: HSBColor = defaultSelectedColor + /// Array of all color controls currently managed by the color picker. These are the controls that the `ColorPickerController` receives updates from and synchonizes with each other. + public private(set) var colorControls = [ColorControl]() + /// Color picker delegate that gets called when selected color is updated or confirmed. The delegate is not retained. + open weak var delegate: ColorPickerDelegate? + + /// Color currently selected by color picker. + @IBInspectable + open var selectedColor: UIColor { + get { + return selectedHSBColor.toUIColor() + } + set { + setColor(newValue.hsbColor, exceptControl: nil, isInteractive: false) + } + } + + @IBOutlet open var colorPreview: ColorPreviewWithHex? { + didSet { + controlDidSet(newValue: colorPreview, oldValue: oldValue) + } + } + + @IBOutlet open var radialHsbPalette: RadialPaletteControl? { + didSet { + controlDidSet(newValue: radialHsbPalette, oldValue: oldValue) + } + } + + @IBOutlet open var rectangularHsbPalette: RectangularPaletteControl? { + didSet { + controlDidSet(newValue: rectangularHsbPalette, oldValue: oldValue) + } + } + + @IBOutlet open var saturationSlider: SaturationSliderControl? { + didSet { + controlDidSet(newValue: saturationSlider, oldValue: oldValue) + } + } + + @IBOutlet open var brightnessSlider: BrightnessSliderControl? { + didSet { + controlDidSet(newValue: brightnessSlider, oldValue: oldValue) + } + } + + @IBOutlet open var redSlider: RedSliderControl? { + didSet { + controlDidSet(newValue: redSlider, oldValue: oldValue) + } + } + + @IBOutlet open var greenSlider: GreenSliderControl? { + didSet { + controlDidSet(newValue: greenSlider, oldValue: oldValue) + } + } + + @IBOutlet open var blueSlider: BlueSliderControl? { + didSet { + controlDidSet(newValue: blueSlider, oldValue: oldValue) + } + } + + @IBOutlet open var customControl1: AbstractColorControl? { + didSet { + controlDidSet(newValue: customControl1, oldValue: oldValue) + } + } + + @IBOutlet open var customControl2: AbstractColorControl? { + didSet { + controlDidSet(newValue: customControl2, oldValue: oldValue) + } + } + + @IBOutlet open var customControl3: AbstractColorControl? { + didSet { + controlDidSet(newValue: customControl3, oldValue: oldValue) + } + } + + /// Adds a `ColorControl` to be managed. Color updates of added control are synchronized with other `ColorControl`s managed by this `ColorPickerController`. Overrides must call super implementation. + /// + /// - Parameter colorControl: Control to be added. + open func addControl(_ colorControl: ColorControl) { + colorControls.append(colorControl) + colorControl.addTarget(self, action: #selector(colorPicked(by:)), for: .valueChanged) + if type(of: colorControl).canConfirmColor { + colorControl.addTarget(self, action: #selector(colorConfirmed(by:)), for: .primaryActionTriggered) + } + } + + + /// Removes a `ColorControl` so that is no longer managed. Color updates of removed control will no longer be synchronized with other `ColorControl`s managed by this `ColorPickerController`. Overrides must call super implementation. + /// + /// - Parameter colorControl: Control to be removed. + open func removeControl(_ colorControl: ColorControl) { + colorControls = colorControls.filter { $0 !== colorControl} + colorControl.removeTarget(self, action: nil, for: [.valueChanged, .primaryActionTriggered]) + } + + /// Called by a managed color control when new color is picked (valueChanged action occures). Distributes the event to all other color controls and notifies the `delegate`. + /// + /// - Parameter control: The control where color change originated. + @objc + open func colorPicked(by control: Any?) { + guard let control = control as? ColorControl else { + return + } + let selectedColor = control.selectedHSBColor + setColor(selectedColor, exceptControl: control, isInteractive: true) + delegate?.colorPicker(self, selectedColor: self.selectedColor, usingControl: control) + } + + + /// Called by a managed color control when user confirms currently selected color using that control (primaryActionTriggered event occures). Notifies the delegate. + /// + /// - Parameter control: Control used to confirm currently selected color. + @objc + open func colorConfirmed(by control: Any?) { + guard let control = control as? ColorControl else { + return + } + if selectedHSBColor != control.selectedHSBColor { + colorPicked(by: control) + } + delegate?.colorPicker(self, confirmedColor: selectedColor, usingControl: control) + } + + + /// Override point, should not be called directly. Synchronizes `selectedHSBColor` values of all managed color controls. + /// + /// - Parameters: + /// - selectedColor: New value of selected color to be set to all managed controls. + /// - control: The source control of new value of selected color, if any. + /// - isInteractive: `true` if the value change of selected color is caused by user interaction with one of the color controls. + open func setColor(_ selectedColor: HSBColor, exceptControl control: ColorControl?, isInteractive: Bool) { + for c in colorControls where c !== control { + c.setSelectedHSBColor(selectedColor, isInteractive: isInteractive) + } + selectedHSBColor = selectedColor + } + + + /// Adds a new color control to be managed by this `ColorPickerController` and removes an old one. Color updates of added control are synchronized with other `ColorControl`s managed by this controller. + /// + /// - Parameters: + /// - newValue: New color control to be added. + /// - oldValue: Color control to be removed. + open func controlDidSet(newValue: ColorControl?, oldValue: ColorControl?) { + oldValue?.remove(from: self) + newValue?.setSelectedHSBColor(selectedHSBColor, isInteractive: false) + newValue?.add(to: self) + } +} + +extension ColorControl { + func add(to picker: ColorPickerController) { + picker.addControl(self) + } + + func remove(from picker: ColorPickerController) { + picker.removeControl(self) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerControllerProtocol.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerControllerProtocol.swift new file mode 100644 index 0000000..cc57458 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerControllerProtocol.swift @@ -0,0 +1,37 @@ +// +// ColorPickerController.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 7/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Protocol implemented by controllers that connect and synchronize *color controls* (`UIView`s, see protocol `ColorControl`) used to pick color. These can be view controllers that also display those *color controls*. +public protocol ColorPickerControllerProtocol: AnyObject { + /// Delegate notified when selected color is changed or when user confirms currently selected color. + var delegate: ColorPickerDelegate? { get set } + /// Currently selected color. + var selectedColor: UIColor { get set } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerDelegate.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerDelegate.swift new file mode 100644 index 0000000..f9d084d --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/ColorPickerDelegate.swift @@ -0,0 +1,63 @@ +// +// FlexColorPickerDelegate.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 4/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Delegate that gets called when color picker's value (picked color) is changed or when user finishes color picking. +/// +/// **See also:** +/// [DefaultColorPickerViewController](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/DefaultColorPickerViewController.swift), [ColorPickerController](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/ColorPickerController.swift) +public protocol ColorPickerDelegate: AnyObject { + + /// Called when a user changes color picker's current selected color. + /// + /// Current selected color can change frequently. If you are just interested in final selected color consider only using `colorPicker(_:, confirmedColor:, usingControl:)` + /// + /// - Parameters: + /// - colorPicker: Controller of the color picker whose `selectedColor` has changed. This is the representiation (principal class) of a color picker instance. + /// - selectedColor: New value of currently selected color. + /// - usingControl: The color control that was used to pick the new `selectedColor`. + func colorPicker(_ colorPicker: ColorPickerController, selectedColor: UIColor, usingControl: ColorControl) + + /// Called when a user has finished picking a color. + /// + /// - Parameters: + /// - colorPicker: Controller of color picker that finished picking color. This is the representiation (principal class) of color picker instance. + /// - confirmedColor: The final selected color. + /// - usingControl: The control that was used to confirm selected color (control that sent `primaryActionTriggered` event). + func colorPicker(_ colorPicker: ColorPickerController, confirmedColor: UIColor, usingControl: ColorControl) +} + +public extension ColorPickerDelegate { + + // an empty implemnetation to make this method of ColorPickerDelegate optional + func colorPicker(_ colorPicker: ColorPickerController, selectedColor: UIColor, usingControl: ColorControl) { } + + // an empty implemnetation to make this method of ColorPickerDelegate optional + func colorPicker(_ colorPicker: ColorPickerController, confirmedColor: UIColor, usingControl: ColorControl) { } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ColorPaletteDelegate.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ColorPaletteDelegate.swift new file mode 100644 index 0000000..73211c5 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ColorPaletteDelegate.swift @@ -0,0 +1,39 @@ +// +// ColorPaletteDelegate.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 27/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +public protocol ColorPaletteDelegate: AnyObject { + var size: CGSize { get set } + func modifiedColor(from color: HSBColor, with point: CGPoint) -> HSBColor + func foregroundImage() -> UIImage + func backgroundImage() -> UIImage? + func closestValidPoint(to: CGPoint) -> CGPoint + func positionAndAlpha(for color: HSBColor) -> (position: CGPoint, foregroundImageAlpha: CGFloat) + func supportedContentMode(for contentMode: UIView.ContentMode) -> UIView.ContentMode +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ColorSliderDelegate.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ColorSliderDelegate.swift new file mode 100644 index 0000000..d3f1dff --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ColorSliderDelegate.swift @@ -0,0 +1,34 @@ +// +// ColorSliderDelegate.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +public protocol ColorSliderDelegate { + func modifiedColor(from color: HSBColor, with value: CGFloat) -> HSBColor + func valueAndGradient(for color: HSBColor) -> (value: CGFloat, gradientStart: UIColor, gradientEnd: UIColor) +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ComponentSliderDelegates.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ComponentSliderDelegates.swift new file mode 100644 index 0000000..463790f --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/ComponentSliderDelegates.swift @@ -0,0 +1,89 @@ +// +// ComponentSliderDelagates.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 2/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +public struct SaturationSliderDelegate: ColorSliderDelegate { + public init() {} + + public func modifiedColor(from color: HSBColor, with value: CGFloat) -> HSBColor { + return color.withSaturation(value) + } + + public func valueAndGradient(for color: HSBColor) -> (value: CGFloat, gradientStart: UIColor, gradientEnd: UIColor) { + return (color.saturation, color.withSaturation(0).toUIColor(), color.withSaturation(1).toUIColor()) + } +} + +public struct BrightnessSliderDelegate: ColorSliderDelegate { + public init() {} + + public func modifiedColor(from color: HSBColor, with value: CGFloat) -> HSBColor { + return color.withBrightness(1 - value) + } + + public func valueAndGradient(for color: HSBColor) -> (value: CGFloat, gradientStart: UIColor, gradientEnd: UIColor) { + return (1 - color.brightness, color.withBrightness(1).toUIColor(), color.withBrightness(0).toUIColor()) + } +} + +public struct RedSliderDelegate: ColorSliderDelegate { + public init() {} + + public func modifiedColor(from color: HSBColor, with value: CGFloat) -> HSBColor { + return color.withRed(value) + } + + public func valueAndGradient(for color: HSBColor) -> (value: CGFloat, gradientStart: UIColor, gradientEnd: UIColor) { + return (color.rgb.red, color.withRed(0).toUIColor(), color.withRed(1).toUIColor()) + } +} + +public struct GreenSliderDelegate: ColorSliderDelegate { + public init() {} + + public func modifiedColor(from color: HSBColor, with value: CGFloat) -> HSBColor { + return color.withGreen(value) + } + + public func valueAndGradient(for color: HSBColor) -> (value: CGFloat, gradientStart: UIColor, gradientEnd: UIColor) { + return (color.rgb.green, color.withGreen(0).toUIColor(), color.withGreen(1).toUIColor()) + } +} + +public struct BlueSliderDelegate: ColorSliderDelegate { + public init() {} + + public func modifiedColor(from color: HSBColor, with value: CGFloat) -> HSBColor { + return color.withBlue(value) + } + + public func valueAndGradient(for color: HSBColor) -> (value: CGFloat, gradientStart: UIColor, gradientEnd: UIColor) { + return (color.rgb.blue, color.withBlue(0).toUIColor(), color.withBlue(1).toUIColor()) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/RadialHSBPaletteDelegate.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/RadialHSBPaletteDelegate.swift new file mode 100644 index 0000000..04e7c4e --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/RadialHSBPaletteDelegate.swift @@ -0,0 +1,132 @@ +// +// RadialHSBPaletteDelegate.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 27/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +open class RadialHSBPaletteDelegate: ColorPaletteDelegate { + public private(set) var diameter: CGFloat = 0 + public private(set) var radius: CGFloat = 0 + public private(set) var midX: CGFloat = 0 + public private(set) var midY: CGFloat = 0 + public private(set) var ceiledDiameter: Int = 0 + + open var size: CGSize = .zero { + didSet { + let diameter = min(size.width, size.height) + self.diameter = diameter + self.radius = diameter / 2 + self.midX = diameter / 2 + min(0, (size.width - diameter) / 2) + self.midY = diameter / 2 + min(0, (size.height - diameter) / 2) + self.ceiledDiameter = Int(ceil(diameter)) + } + } + + public init() {} + + @inline(__always) + open func hueAndSaturation(at point: CGPoint) -> (hue: CGFloat, saturation: CGFloat) { + let dy = (point.y - midY) / radius + let dx = (point.x - midX) / radius + let distance = sqrt(dx * dx + dy * dy) + if distance <= 0 { + return (0, 0) + } + let hue = acos(dx / distance) / CGFloat.pi / 2 + return (dy < 0 ? 1 - hue : hue, min(1, distance)) + } + + open func modifiedColor(from color: HSBColor, with point: CGPoint) -> HSBColor { + let (hue, saturation) = hueAndSaturation(at: point) + return color.withHue(hue, andSaturation: saturation) + } + + open func foregroundImage() -> UIImage { + var imageData = [UInt8](repeating: 255, count: (4 * ceiledDiameter * ceiledDiameter)) + for i in 0 ..< ceiledDiameter{ + for j in 0 ..< ceiledDiameter { + let index = 4 * (i * ceiledDiameter + j) + let (hue, saturation) = hueAndSaturation(at: CGPoint(x: j, y: i)) // rendering image transforms it as it it was mirrored around x = -y axis - adjusting for it by switching i and j here + let (r, g, b) = rgbFrom(hue: hue, saturation: saturation, brightness: 1) + imageData[index] = colorComponentToUInt8(r) + imageData[index + 1] = colorComponentToUInt8(g) + imageData[index + 2] = colorComponentToUInt8(b) + imageData[index + 3] = 255 + } + } + + guard let image = UIImage(rgbaBytes: imageData, width: ceiledDiameter, height: ceiledDiameter) else { + return UIImage() + } + + // clip the image to circle + let imageRect = CGRect(x: 0,y: 0, width: diameter, height: diameter) + UIGraphicsBeginImageContextWithOptions(imageRect.size, false, 0) + UIBezierPath(ovalIn: imageRect).addClip() + image.draw(in: imageRect) + defer { + UIGraphicsEndImageContext() + } + if let clippedImage = UIGraphicsGetImageFromCurrentImageContext() { + return clippedImage + } + return UIImage() + } + + open func backgroundImage() -> UIImage? { + let imageSize = CGSize(width: diameter, height: diameter) + if imageSize == .zero { + return nil + } + return UIImage.drawImage(ofSize: imageSize, path: UIBezierPath(ovalIn: CGRect(origin: .zero, size: imageSize)), fillColor: .black) + } + + open func closestValidPoint(to point: CGPoint) -> CGPoint { + let distance = point.distanceTo(x: midX, y: midY) + if distance <= radius { + return point + } + let x = midX + radius * ((point.x - midX) / distance) + let y = midY + radius * ((point.y - midY) / distance) + return CGPoint(x: x, y: y) + } + + open func positionAndAlpha(for color: HSBColor) -> (position: CGPoint, foregroundImageAlpha: CGFloat) { + let (hue, saturation, brightness) = color.asTupleNoAlpha() + let radius = saturation * self.radius + let x = self.radius + radius * cos(hue * 2 * CGFloat.pi) + let y = self.radius + radius * sin(hue * 2 * CGFloat.pi) + return (CGPoint(x: x, y: y), brightness) + } + + open func supportedContentMode(for contentMode: UIView.ContentMode) -> UIView.ContentMode { + switch contentMode { + case .redraw, .scaleToFill, .scaleAspectFill: return .scaleAspectFit + default: return contentMode + } + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/RectangularHSBPaletteDelegate.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/RectangularHSBPaletteDelegate.swift new file mode 100644 index 0000000..d9dd6f9 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/ControlDelegates/RectangularHSBPaletteDelegate.swift @@ -0,0 +1,94 @@ +// +// RectangularHSBPaletteDelegate.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 2/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +open class RectangularHSBPaletteDelegate: ColorPaletteDelegate { + public private(set) var intWidth = 0 + public private(set) var intHeight = 0 + + public var size: CGSize = .zero { + didSet { + intWidth = Int(size.width) + intHeight = Int(size.height) + } + } + /// When `true` the different values of color hue will correspond to different coordinates along x axis (that means that vertical lines will have same hue but different saturation). When `false`, different values of color hue will correspond to different coordinates along y axis. + public var hueHorizontal = true + + public init() {} + + @inline(__always) + open func hueAndSaturation(at point: CGPoint) -> (hue: CGFloat, saturation: CGFloat) { + let hue = hueHorizontal ? point.x / size.width : point.y / size.height + let saturation = hueHorizontal ? point.y / size.height : point.x / size.width + return (max (0, min(1, hue)), 1 - max(0, min(1, saturation))) + } + + public func modifiedColor(from color: HSBColor, with point: CGPoint) -> HSBColor { + let (hue, saturation) = hueAndSaturation(at: point) + return color.withHue(hue, andSaturation: saturation) + } + + open func foregroundImage() -> UIImage { + var imageData = [UInt8](repeating: 1, count: (4 * intWidth * intHeight)) + for i in 0 ..< intWidth { + for j in 0 ..< intHeight { + let index = 4 * (i + j * intWidth) + let (hue, saturation) = hueAndSaturation(at: CGPoint(x: i, y: j)) // rendering image transforms it as it it was mirrored around x = -y axis - adjusting for it by switching i and j here + let (r, g, b) = rgbFrom(hue: hue, saturation: saturation, brightness: 1) + imageData[index] = colorComponentToUInt8(r) + imageData[index + 1] = colorComponentToUInt8(g) + imageData[index + 2] = colorComponentToUInt8(b) + imageData[index + 3] = 255 + } + } + return UIImage(rgbaBytes: imageData, width: intWidth, height: intHeight) ?? UIImage() + } + + open func backgroundImage() -> UIImage? { + let size = CGSize(width: intWidth, height: intHeight) // overriding size property to get same size of background image in situations when foreground image dimestions are rounded down to int + if size.width == 0 || size.height == 0 { + return nil + } + return UIImage.drawImage(ofSize: size, path: UIBezierPath(rect: CGRect(origin: .zero, size: size)), fillColor: .black) + } + + open func closestValidPoint(to point: CGPoint) -> CGPoint { + return CGPoint(x: min(size.width, max(0, point.x)), y: min(size.height, max(0, point.y))) + } + + open func positionAndAlpha(for color: HSBColor) -> (position: CGPoint, foregroundImageAlpha: CGFloat) { + let (hue, saturation, brightness) = color.asTupleNoAlpha() + return (CGPoint(x: (hueHorizontal ? hue : 1 - saturation) * size.width, y: (hueHorizontal ? 1 - saturation : hue) * size.height), brightness) + } + + open func supportedContentMode(for contentMode: UIView.ContentMode) -> UIView.ContentMode { + return contentMode + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/AbstractColorControl.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/AbstractColorControl.swift new file mode 100644 index 0000000..c784a91 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/AbstractColorControl.swift @@ -0,0 +1,107 @@ +// +// UIControlWithCommonInit.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +let defaultBorderWidth: CGFloat = 1 / UIScreen.main.scale + +/// Contains common functionality for `ColorControl`. It is recomended to subclass this rather than `UIView` or `UIControl` when implementing custom color control. +/// +/// Any subvies must be added to `contentView` only for this to work correctly inside `UIScrollView` and iOS 13 modal view controllers. +/// +/// If you directly subclass this rather than `ColorPaletteControl` or `ColorSliderControl` override `gestureRecognizerShouldBegin(:)` to ensure that your custom color control works correctly inside `UIScrollView` and iOS 13 modal view controllers (that can be dragged to down to dismiss). Default implementation of the method disables any `UIPanGestureRecognizer`. E.g. you might want to allow some pan directions. +/// +/// See README for more information on subclassing. +open class AbstractColorControl: UIControl, ColorControl, ColorControlContentViewDelegate { + /// Content holder for AbstractColorControl. All subviews must be added here. + public let contentView: UIView = ColorControlContentView() + private(set) public var selectedHSBColor: HSBColor = defaultSelectedColor + + /// Currently selected color of the color control as `UIColor`. Convinience property: Value is backed by and changes are reflected to `selectedHSBColor`. + @IBInspectable + public var selectedColor: UIColor { //overriding default implementation from ColorControl to add @IBInspectable + get { + return selectedHSBColor.toUIColor() + // do not do something like return (self as ColorControl).selectedColor here as that breaks IBDesignable + } + set { + selectedHSBColor = newValue.hsbColor // do not do something like (self as ColorControl).selectedColor = newValue here as that breaks IBDesignable + } + } + + public override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + commonInit() + } + + open override func awakeFromNib() { + super.awakeFromNib() + commonInit() + } + + open override func prepareForInterfaceBuilder() { + super.prepareForInterfaceBuilder() + commonInit() + } + + /// This method is override point for initialization tasks that needs to be carried no matter how the view is constructed (e. g. via Interface Builder or from code). Overriders must call super implementation. + open func commonInit() { + (contentView as! ColorControlContentView).delegate = self + addAutolayoutFillingSubview(contentView) + isExclusiveTouch = true + } + + open func setSelectedHSBColor(_ hsbColor: HSBColor, isInteractive: Bool) { + selectedHSBColor = hsbColor + } + + func locationForTouches(_ touches: Set) -> CGPoint? { + return touches.first?.location(in: self) + } + + func updateBorder(visible: Bool, view: UIView) { + if visible { + view.viewBorderColor = UIColor.colorPickerBorderColor + } + view.borderWidth = visible ? defaultBorderWidth : 0 + } +} + +extension AbstractColorControl { + open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + guard let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else { + return false + } + return !bounds.contains(gestureRecognizer.location(in: self)) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/AdjustedHitBoxColorControl.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/AdjustedHitBoxColorControl.swift new file mode 100644 index 0000000..68fc50a --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/AdjustedHitBoxColorControl.swift @@ -0,0 +1,84 @@ +// +// AdjustedHitBoxColorControl.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 6/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +let defaultHitBoxInset: CGFloat = 16 +public let colorControlWithThumbViewDefaultHitBoxInsets = UIEdgeInsets(top: defaultHitBoxInset, left: defaultHitBoxInset, bottom: defaultHitBoxInset, right: defaultHitBoxInset) + +/// Color control with frame (and hit box) extended beyond its alignment rectangle. +/// +/// It is generally recomeneded to subclass this class rather than `AbstractColorControl` when creating custom color controls to have better control over your control's hit box. +/// +/// Any subvies must be added to `contentView` only for this to work correctly inside `UIScrollView` and iOS 13 modal view controllers. +/// +/// If you directly subclass this rather than `ColorPaletteControl` or `ColorSliderControl` override `gestureRecognizerShouldBegin(:)` to ensure that your custom color control works correctly inside `UIScrollView` and iOS 13 modal view controllers (that can be dragged to down to dismiss). Default implementation of the method disables any `UIPanGestureRecognizer`. E.g. you might want to allow some pan directions. +/// +/// - Important: The disproportion between the `AdjustedHitBoxColorControl`'s frame (and bounds) and its alignment rectangle means that when aligning it using autolayout the frame might extend behond rectangle specified by layout constraits. When using lautolayout mind that the frame might therefore overlap other views. +/// +/// See README for more information on subclassing. +open class AdjustedHitBoxColorControl: AbstractColorControl { + + /// The alighnment rectangle of the color control in its own coordinate system. + public var contentBounds: CGRect { + layoutIfNeeded() + return contentView.frame + } + + /// A single hit box inset value for all inset directions (top, bottom, left, right) meant to only be used from interface builder. + /// - Important: Do **not** use this property from code. Use hitBoxInset**s** property instead. + @IBInspectable + public var hitBoxInset: CGFloat { + get { + return (hitBoxInsets.bottom + hitBoxInsets.left + hitBoxInsets.top + hitBoxInsets.right) / 4 + } + set { + hitBoxInsets = UIEdgeInsets(top: newValue, left: newValue, bottom: newValue, right: newValue) + } + } + + /// Insets of the alignment rectangle relative to frame (frame is also hit box rectangle). + /// + /// Applying this insets to `frame` results in alignment rectangle. + public var hitBoxInsets = colorControlWithThumbViewDefaultHitBoxInsets { + didSet { + setNeedsLayout() + } + } + + open override var alignmentRectInsets: UIEdgeInsets { + return hitBoxInsets + } + + override func locationForTouches(_ touches: Set) -> CGPoint? { + guard let location = super.locationForTouches(touches) else { + return nil + } + return convert(location, to: contentView) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorControl.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorControl.swift new file mode 100644 index 0000000..c6fffc6 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorControl.swift @@ -0,0 +1,70 @@ +// +// ColorPickerControl.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Protocol to which all color picker controls must conform. This protocol defines contract of *color controls*. +/// +/// A *color control* is standalone view that should subclass `UIControl` and which can be used to pick a color. Value of *color control* is stored in `selectedHSBColor` property. +/// +/// *Color control* sends `UIControlEvents.valueChanged` events to registered targets when its value (`selectedHSBColor`) changes as consequence of user interaction with the control. A *color control* can also send `UIControlEvents.primaryActionTriggered` when user takes action to confirm current selected color as final. +/// +/// A *color control* should be usable as standalone component but is usually used together with other *color controls* managed and synchronized by instance of `ColorPickerController`. +public protocol ColorControl: AnyObject { + /// Override this and return `false` if you do not want `UIControlEvents.primaryActionTriggered` events sent by the color control to be considered confirmation of color selection. + static var canConfirmColor: Bool { get } + /// The value of this color control. Represents current selected color. Use `setSelectedHSBColor(_: isInteractive:)` to set value of this property. + var selectedHSBColor: HSBColor { get } + + /// Sets `selectedHSBColor` and adjusts visual state of the control to its new value. + /// + /// - Parameters: + /// - hsbColor: New value to be set as selected color of this color control. + /// - isInteractive: Whether new selected color was specified programatically or by user via interaction with another control. This can used to determine if some animations should be played. + func setSelectedHSBColor(_ hsbColor: HSBColor, isInteractive: Bool) + + func addTarget(_ target: Any?, action: Selector, for: UIControl.Event) + func removeTarget(_ target: Any?, action: Selector?, for: UIControl.Event) +} + +public extension ColorControl { + /// Provides the default value for canConfirmColor. Returns true. + static var canConfirmColor: Bool { + return true + } + + /// Currently selected color of the *color control* as `UIColor`. Convinience property: Value is backed by and changes are reflected to `selectedHSBColor`. + var selectedColor: UIColor { + get { + return selectedHSBColor.toUIColor() + } + set { + setSelectedHSBColor(newValue.hsbColor, isInteractive: false) + } + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorPaletteControl.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorPaletteControl.swift new file mode 100644 index 0000000..aba2ae6 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorPaletteControl.swift @@ -0,0 +1,155 @@ +// +// ColorPaleteControl.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 27/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +let minimumDistanceForInBoundsTouchFromValidPoint: CGFloat = 44 +let defaultSelectedColor = UIColor.white.hsbColor + +/// Color control that allows to select color by tapping or panning a palette that displays available color options. +/// +/// Any subvies must be added to `contentView` only for this to work correctly inside `UIScrollView` and iOS 13 modal view controllers. +@IBDesignable +open class ColorPaletteControl: ColorControlWithThumbView { + /// The image view providing preview of color option for each particular point. Its image might be e.g. hue/saturation map. + public let foregroundImageView = UIImageView() + /// Background image view that holds image which blends with image displayed by `foregroundImageView` when its alpha is less then 1, providing more accurate color options preview. E.g. black image that blends with hue/saturation map in foreground to show color map adjusted for brightness . + public let backgroundImageView = UIImageView() + + /// A delegate that specifies what pallete color options look like (image of the palette) and how selecting a point on the palette is interpreted. It also specifies tappable region of the palette. + open var paletteDelegate: ColorPaletteDelegate = RadialHSBPaletteDelegate() { + didSet { + updatePaletteImagesAndThumb(isInteractive: false) + } + } + open override var bounds: CGRect { + didSet { + guard oldValue != bounds else { + return + } + updatePaletteImagesAndThumb(isInteractive: false) + } + } + + open override var contentMode: UIView.ContentMode { + didSet { + updateContentMode() + updateThumbPosition(position: paletteDelegate.positionAndAlpha(for: selectedHSBColor).position) + } + } + + open override func commonInit() { + super.commonInit() + contentView.addAutolayoutFillingSubview(backgroundImageView) + backgroundImageView.addAutolayoutFillingSubview(foregroundImageView) + updateContentMode() + contentView.addSubview(thumbView) + updatePaletteImagesAndThumb(isInteractive: false) + } + + open override func setSelectedHSBColor(_ hsbColor: HSBColor, isInteractive interactive: Bool) { + let hasChanged = selectedHSBColor != hsbColor + super.setSelectedHSBColor(hsbColor, isInteractive: interactive) + if hasChanged { + thumbView.setColor(hsbColor.toUIColor(), animateBorderColor: interactive) + let (position, foregroundAlpha) = paletteDelegate.positionAndAlpha(for: hsbColor) + updateThumbPosition(position: position) + foregroundImageView.alpha = foregroundAlpha + } + } + + /// Updates palette foreground and backround images and thumb view to reflect current state of this control (e.g. values of `selectedHSBColor` and `paletteDelegate`). Call this only if update of visual state of the pallete is necessary as this call has performance implications - new images are requested from palette delegate. + /// + /// Override this if you need update palette visual state differently on state change. + /// + /// - Parameter interactive: Whether the change originated from user interaction or is programatic. This can be used to determine if certain animations should be played. + open func updatePaletteImagesAndThumb(isInteractive interactive: Bool) { + layoutIfNeeded() //force subviews layout to update their bounds - bounds of subviews are not automatically updated + paletteDelegate.size = foregroundImageView.bounds.size //cannot use self.bounds as that is extended compared to foregroundImageView.bounds when AdjustedHitBoxColorControl.hitBoxInsets are non-zero + foregroundImageView.image = paletteDelegate.foregroundImage() + backgroundImageView.image = paletteDelegate.backgroundImage() + assert(foregroundImageView.image!.size.width <= paletteDelegate.size.width && foregroundImageView.image!.size.height <= paletteDelegate.size.height, "Size of rendered image must be smaller or equal specified palette size") + assert(backgroundImageView.image == nil || foregroundImageView.image?.size == backgroundImageView.image?.size, "foreground and background images rendered must have same size") + updateContentMode() + updateThumbPosition(position: paletteDelegate.positionAndAlpha(for: selectedHSBColor).position) + thumbView.setColor(selectedColor, animateBorderColor: interactive) + } + + /// Translates a point from given coordinate space to coordinate space of foreground image. Image coordinate space is used by the palette delegate. + /// - Note: This translates from the coordiate space of the image itself not the coordinate space of its image view. Those can be different and the translation between them is dependent on current value of image view's `contentMode`. + /// + /// - Parameters: + /// - point: The point to translate. + /// - coordinateSpace: Source (current) coordinate space of the point to translate from. + /// - Returns: Corresponding point in image coordinate space. + open func imageCoordinates(point: CGPoint, fromCoordinateSpace coordinateSpace: UICoordinateSpace) -> CGPoint { + return foregroundImageView.convertToImageSpace(point: foregroundImageView.convert(point, from: coordinateSpace)) + } + + /// Translates a point from coordinate space of foreground image to given coordinate space. Image coordinate space is used by the palette delegate. + /// - Note: This translates to the coordiate space of the image itself not the coordinate space of its image view. Those can be different and the translation between them is dependent on current value of image view's `contentMode`. + /// + /// - Parameters: + /// - point: The point to translate. + /// - coordinateSpace: Target (destination) coordinate space to translate to. + /// - Returns: Corresponding point in target coordinate space. + open func imageCoordinates(point: CGPoint, toCoordinateSpace coordinateSpace: UICoordinateSpace) -> CGPoint { + return foregroundImageView.convert(foregroundImageView.convertFromImageSpace(point: point), to: coordinateSpace) + } + + open override func updateSelectedColor(at point: CGPoint, isInteractive: Bool) { + let pointInside = paletteDelegate.closestValidPoint(to: imageCoordinates(point: point, fromCoordinateSpace: contentView)) + setSelectedHSBColor(paletteDelegate.modifiedColor(from: selectedHSBColor, with: pointInside), isInteractive: isInteractive) + updateThumbPosition(position: pointInside) + sendActions(for: .valueChanged) + } + + open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let maxTouchDistance = max(hitBoxInsets.bottom, hitBoxInsets.top, hitBoxInsets.left, hitBoxInsets.right, minimumDistanceForInBoundsTouchFromValidPoint) + if imageCoordinates(point: paletteDelegate.closestValidPoint(to: imageCoordinates(point: point, fromCoordinateSpace: self)), toCoordinateSpace: self).distance(to: point) > maxTouchDistance { + return nil + } + return super.hitTest(point, with: event) + } + + private func updateThumbPosition(position: CGPoint) { + thumbView.frame = CGRect(center: imageCoordinates(point: position, toCoordinateSpace: contentView), size: thumbView.intrinsicContentSize) + } + + private func updateContentMode() { + let contentMode = paletteDelegate.supportedContentMode(for: self.contentMode) + backgroundImageView.contentMode = contentMode + foregroundImageView.contentMode = contentMode + } +} + +extension ColorPaletteControl { + open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + return !(gestureRecognizer is UIPanGestureRecognizer) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorPreviewWithHex.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorPreviewWithHex.swift new file mode 100644 index 0000000..53b5ed7 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorPreviewWithHex.swift @@ -0,0 +1,219 @@ +// +// ColorPreviewWithHex.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 1/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +internal let colorPreviewWithHexIntristicContentSize = CGSize(width: 65, height: 90) +internal let defaultHexLabelHeight: CGFloat = 20 +private let hexFont = UIFont.systemFont(ofSize: 12) +private let defaultCornerradius: CGFloat = 5 + +private let confirmAnimationScaleRatio: CGFloat = 0.87 +private let confirmAnimationSpringDamping: CGFloat = 0.7 +private let confirmAnimationDuration = 0.3 + +/// A color control that displays currently selected color. It allows the user to evaluate if it is the color they want. +/// +/// When tapped, it animates and sends `primaryActionTriggered` event. This event is interpreted as user confirming current color as final picked color by the `ColorPickerController`. +@IBDesignable +open class ColorPreviewWithHex: AbstractColorControl { + private var labelHeightConstraint = NSLayoutConstraint() + + /// A subview that shows example of selected color. It is set as its `backgroundColor`. + public let colorView = UIView() + /// A label subview that shows hex value of selected color as text. + public let hexLabel = UILabel() + + /// Convinience layout anchor that corresponds to bottom edge of `colorView`. This might not be equivalent of `bottomAnchor` as the `hexLabel` is below `colorView` (it it is displayed). + /// + /// Use this to align other views to `colorView`. + open var hexLabelToLayoutAnchor: NSLayoutYAxisAnchor { + return hexLabel.topAnchor + } + + /// Whether to show (`true`) or hide (`false`) the subview that shows hex value of currently selected color (the `hexLabel`). + @IBInspectable + public var displayHex: Bool = true { + didSet { + updateLabelHeight() + } + } + + /// The desired height of the area displaying hex value of currently selected color. + @IBInspectable + public var hexHeight: CGFloat = defaultHexLabelHeight { + didSet { + updateLabelHeight() + } + } + + /// Text color of the hex label that displys hex value of currently selected color. + @IBInspectable + public var textColor: UIColor = UIColor.colorPickerLabelTextColor { + didSet { + hexLabel.textColor = textColor + } + } + + /// Whether to display default thin border around the preview. + @IBInspectable + public var borderOn: Bool = true { + didSet { + updateBorder(visible: borderOn, view: self) + } + } + + /// Corner radius of the preview. + /// + /// You can set it to very high value to make the view oval (or circular if bounds are square). + @IBInspectable + public var cornerRadius: CGFloat = defaultCornerradius { + didSet { + updateCornerRadius() + } + } + + ///If `true`, the preview will respond to touches, animating and sending `primaryActionTriggered` event on `touchUpInside`. + @IBInspectable + public var tapToConfirm: Bool = true + + open override var bounds: CGRect { + didSet { + updateCornerRadius() + } + } + + open override var intrinsicContentSize: CGSize { + return colorPreviewWithHexIntristicContentSize + } + + open override func commonInit() { + super.commonInit() + + addSubview(colorView) + colorView.translatesAutoresizingMaskIntoConstraints = false + + addSubview(hexLabel) + hexLabel.translatesAutoresizingMaskIntoConstraints = false + + colorView.topAnchor.constraint(equalTo: topAnchor).isActive = true + colorView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true + colorView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true + colorView.bottomAnchor.constraint(equalTo: hexLabel.topAnchor).isActive = true + + hexLabel.leftAnchor.constraint(equalTo: leftAnchor).isActive = true + hexLabel.rightAnchor.constraint(equalTo: rightAnchor).isActive = true + labelHeightConstraint = hexLabel.heightAnchor.constraint(equalToConstant: hexHeight) + labelHeightConstraint.priority = .init(999) + labelHeightConstraint.isActive = true + hexLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + updateLabelHeight() + + hexLabel.textColor = textColor + hexLabel.textAlignment = .center + hexLabel.font = hexFont + updateBorder(visible: borderOn, view: self) + setSelectedHSBColor(selectedHSBColor, isInteractive: false) // set default color if it is not set, otherwise keep color set in storyboard via IBInspectable + updateCornerRadius() + } + + open override func setSelectedHSBColor(_ hsbColor: HSBColor, isInteractive interactive: Bool) { + super.setSelectedHSBColor(hsbColor, isInteractive: interactive) + let color = hsbColor.toUIColor() + colorView.backgroundColor = color + hexLabel.text = "#\(color.hexValue())" + } + + private func updateLabelHeight() { + labelHeightConstraint.constant = displayHex ? hexHeight : 0 + } + + /// Updates border color of the color preview when interface is changed to dark or light mode. + open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + if #available(iOS 13.0, *), traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle { + updateBorder(visible: borderOn, view: self) + } + } + + private func handleTouchDown() { + if !tapToConfirm { + return + } + UIView.animate(withDuration: confirmAnimationDuration, delay: 0, usingSpringWithDamping: confirmAnimationSpringDamping, initialSpringVelocity: 0, options: [], animations: { + self.layer.transform = CATransform3DMakeScale(confirmAnimationScaleRatio, confirmAnimationScaleRatio, 1) + }, completion: nil) + } + + private func handleTouchUp(valid: Bool) { + if !tapToConfirm { + return + } + UIView.animate(withDuration: confirmAnimationDuration, delay: 0, usingSpringWithDamping: confirmAnimationSpringDamping, initialSpringVelocity: 0, options: [], animations: { + self.layer.transform = CATransform3DIdentity + }) { _ in + if valid { + self.sendActions(for: .primaryActionTriggered) + } + } + } + + private func updateCornerRadius() { + cornerRadius_ = min(cornerRadius, bounds.height / 2, bounds.width / 2) + if cornerRadius_ > 0 { + clipsToBounds = true + } + } +} + +extension ColorPreviewWithHex { + open override func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard let location = locationForTouches(touches), point(inside: location, with: event) else { + return + } + handleTouchDown() + super.touchesBegan(touches, with: event) + } + + open override func touchesEnded(_ touches: Set, with event: UIEvent?) { + guard let location = locationForTouches(touches) else { + return + } + handleTouchUp(valid: point(inside: location, with: event)) + super.touchesEnded(touches, with: event) + } + + open override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + handleTouchUp(valid: false) + super.touchesCancelled(touches, with: event) + } + + open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + return true + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorSliderControl.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorSliderControl.swift new file mode 100644 index 0000000..2e4f6db --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ColorSliderControl.swift @@ -0,0 +1,195 @@ +// +// ColorSliderControl.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +public let OUTSIDE_DRAG_HORIZONTAL_TO_VERTICAL_TRANSLATION_RATIO: CGFloat = 2.5 + +private let defaultGradientViewHeight: CGFloat = 15 + +/// Color control that allows to change selected color by tapping a point on (or panning over) a line. The control displays color preview for all positions in that line. +/// +/// Any subvies must be added to `contentView` only for this to work correctly inside `UIScrollView` and iOS 13 modal view controllers. +@IBDesignable +open class ColorSliderControl: ColorControlWithThumbView { + + /// This is view behind gradient that can be used to show custom color options preview if the preview cannot be represented by simple gradient. + public let gradientBackgroundView = UIImageView() + /// Previews color options avaialable va chnaging value of the slider in form of linear gradient. + public let gradientView = GradientView() + + /// When `true` the thumb shows 100% label for left-most possition of the slider and 0% for right-most possition. Default is `false` (0% is displayed on left). Has no effect if `thumbLabelFormatter` is set. + /// + /// This is usefull e.g. when "physically correct" percentage label behaviour of `BrightnessSliderControl` is preferred (as the most "bright" color is on the left of the slider in that case). + public var reversePercentage: Bool = false { + didSet { + let (value, _, _) = sliderDelegate.valueAndGradient(for: selectedHSBColor) + updatePercentageLabel(for: value) + } + } + + /// When set to non-nil value it will be used to generate label text of `thumbView` directly instead of via setting `thumbView`s `percentage` property. setting this overrides `percentage` property. + public var thumbLabelFormatter: ((CGFloat) -> String)? { + didSet { + let (value, _, _) = sliderDelegate.valueAndGradient(for: selectedHSBColor) + updatePercentageLabel(for: value) + } + } + + /// Whether to display default thin border around the slider. + @IBInspectable + public var borderOn: Bool = true { + didSet { + updateBorder(visible: borderOn, view: gradientBackgroundView) + } + } + + /// A delegate that specifies gradient of the slider and how selecting a value is interpreted. + open var sliderDelegate: ColorSliderDelegate = BrightnessSliderDelegate() { + didSet { + updateThumbAndGradient(isInteractive: false) + } + } + + open override var bounds: CGRect { + didSet { + guard oldValue != bounds else { + return + } + updateCornerRadius() + updateThumbAndGradient(isInteractive: false) + } + } + + open override var intrinsicContentSize: CGSize { + return CGSize(width: UIScreen.main.bounds.width, height: defaultGradientViewHeight) + } + + open override func commonInit() { + super.commonInit() + contentView.addAutolayoutFillingSubview(gradientBackgroundView) + gradientBackgroundView.addAutolayoutFillingSubview(gradientView) + updateCornerRadius() + gradientBackgroundView.clipsToBounds = true + updateThumbAndGradient(isInteractive: false) + contentView.addSubview(thumbView) + updateBorder(visible: borderOn, view: gradientBackgroundView) + } + + open override func setSelectedHSBColor(_ hsbColor: HSBColor, isInteractive interactive: Bool) { + super.setSelectedHSBColor(hsbColor, isInteractive: interactive) + updateThumbAndGradient(isInteractive: interactive) + } + + private func updateCornerRadius() { + gradientBackgroundView.cornerRadius_ = contentBounds.height / 2 + } + + /// Updates slider's preview (the gradient) to reflect current state of the slider (e.g. value of `selectedHSBColor` and `sliderDelegate`). + /// + /// Override this if you need to update slider's visual state differently on state change. + /// + /// - Parameter interactive: Whether the change originated from user interaction or is programatic. This can be used to determine if certain animations should be played. + open func updateThumbAndGradient(isInteractive interactive: Bool) { + layoutIfNeeded() //force subviews layout to update their bounds - bounds of subviews are not automatically updated + let (value, gradientStart, gradientEnd) = sliderDelegate.valueAndGradient(for: selectedHSBColor) + let gradientLength = contentBounds.width - thumbView.colorIdicatorRadius * 2 //cannot use self.bounds as that is extended compared to foregroundImageView.bounds when AdjustedHitBoxColorControl.hitBoxInsets are non-zero + thumbView.frame = CGRect(center: CGPoint(x: thumbView.colorIdicatorRadius + gradientLength * min(max(0, value), 1), y: contentView.bounds.midY), size: thumbView.intrinsicContentSize) + thumbView.setColor(selectedHSBColor.toUIColor(), animateBorderColor: interactive) + gradientView.startOffset = thumbView.colorIdicatorRadius + gradientView.endOffset = thumbView.colorIdicatorRadius + gradientView.startColor = gradientStart //to keep the gradient realistic (you select exactly the same color that you tapped) we need to offset gradient as tapping first and last part of gradient (of length thumbView.colorIdicatorRadius) always selects max or min color + gradientView.endColor = gradientEnd + } + + open override func updateSelectedColor(at point: CGPoint, isInteractive: Bool) { + let gradientLength = contentBounds.width - thumbView.colorIdicatorRadius * 2 + let value = max(0, min(1, (point.x - thumbView.colorIdicatorRadius) / gradientLength)) + updatePercentageLabel(for: value) + setSelectedHSBColor(sliderDelegate.modifiedColor(from: selectedHSBColor, with: min(max(0, value), 1)), isInteractive: isInteractive) + sendActions(for: .valueChanged) + } + + public func updatePercentageLabel(for value: CGFloat) { + thumbView.percentage = Int(round((reversePercentage ? 1 - value : value) * 100)) + if let thumbLabelFormatter = thumbLabelFormatter { + thumbView.percentageLabel.text = thumbLabelFormatter(value) + } + } + + /// Updates border color of the color slider control when interface is changed to dark or light mode. + open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + if #available(iOS 13.0, *), traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle { + updateBorder(visible: borderOn, view: gradientBackgroundView) + } + } +} + +extension ColorSliderControl { + /// When `true` the slider's thumb will automatically darken its border when selected color is too bright to be contrast enought with white border. + @IBInspectable + public var autoDarken: Bool { + get { + return thumbView.autoDarken + } + set { + thumbView.autoDarken = newValue + } + } + + /// Whether to show selected value as percentage above the thumb view while user is interacting with the slider. + @IBInspectable + public var showPercentage: Bool { + get { + return thumbView.showPercentage + } + set { + thumbView.showPercentage = newValue + } + } + + /// Whether the slider's thumb view should be expanded when a user is interacting with the slider. + @IBInspectable + public var expandOnTap: Bool { + get { + return thumbView.expandOnTap + } + set { + thumbView.expandOnTap = newValue + } + } + + open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + guard let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else { + return false + } + let translation = gestureRecognizer.translation(in: self) + return abs(translation.x) * OUTSIDE_DRAG_HORIZONTAL_TO_VERTICAL_TRANSLATION_RATIO < abs(translation.y) || !bounds.contains(gestureRecognizer.location(in: self)) && abs(translation.x) < abs(translation.y) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift new file mode 100644 index 0000000..7bfe452 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift @@ -0,0 +1,91 @@ +// +// ComponentSliderControls.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 2/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +/// Color slider that allows to change saturation (in terms of HSB color model) of currently selected color by panning the slider line or by tapping it. +/// +/// Tapping left end of the slider will select slider's current color modified to have 0% saturation. Tapping right edge of the slider will select current color modified to have 100% saturation. +@IBDesignable +final public class SaturationSliderControl: ColorSliderControl { + public override func commonInit() { + sliderDelegate = SaturationSliderDelegate() + super.commonInit() + } +} + +/// Color slider that allows to change brightness (in terms of HSB color model) of currently selected color by panning the slider line or by tapping it. +/// +/// Tapping left end of the slider will select slider's current color modified to have 100% brightness. Tapping right edge of the slider will select current color modified to have 0% brightness. +/// +/// - Note: Unlike other provided sliders, this slider's default thumb label percentage shown does not correspond to actual physical properties of the selected color. +/// When thumb is on lift-most side of the slider it shows 0% while the color brightness is actually 100% (and vice-versa for the right-most thumb position). This is intentional as most users expect such behaviour. +/// If "physically correct" percentage label behaviour is preferred (this is usually the case when you your UI labels this slider as "Brightness:" or when your user base might be more knowleadgable about colors theory) set property `reversePercentage` to true. +final public class BrightnessSliderControl: ColorSliderControl { + + /// When `true` the thumb shows 100% label for left-most possition of the slider and 0% for right-most possition. Default is `false` (0% is displayed on left). Has no effect if `thumbLabelFormatter` is set. + /// + /// This is usefull when "physically correct" percentage label behaviour is preferred (as the most "bright" color is on the left of the slider). + @IBInspectable + public override var reversePercentage: Bool { + didSet {} // override only to add inspectable + } + + public override func commonInit() { + sliderDelegate = BrightnessSliderDelegate() + super.commonInit() + } +} + +/// Color slider that allows to change red component (in terms of RGB color model) of currently selected color by panning the slider line or by tapping it. +/// +/// Tapping left end of the slider will select slider's current color modified to have 0% red. Tapping right edge of the slider will select current color modified to have 100% red. +final public class RedSliderControl: ColorSliderControl { + public override func commonInit() { + sliderDelegate = RedSliderDelegate() + super.commonInit() + } +} + +/// Color slider that allows to change green component (in terms of RGB color model) of currently selected color by panning the slider line or by tapping it. +/// +/// Tapping left end of the slider will select slider's current color modified to have 0% green. Tapping right edge of the slider will select current color modified to have 100% green. +final public class GreenSliderControl: ColorSliderControl { + public override func commonInit() { + sliderDelegate = GreenSliderDelegate() + super.commonInit() + } +} + +/// Color slider that allows to change blue component (in terms of RGB color model) of currently selected color by panning the slider line or by tapping it. +/// +/// Tapping left end of the slider will select slider's current color modified to have 0% blue. Tapping right edge of the slider will select current color modified to have 100% blue. +final public class BlueSliderControl: ColorSliderControl { + public override func commonInit() { + sliderDelegate = BlueSliderDelegate() + super.commonInit() + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ControlWithThumbView.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ControlWithThumbView.swift new file mode 100644 index 0000000..c3e9c32 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/ControlWithThumbView.swift @@ -0,0 +1,89 @@ +// +// ColorControlWithThumbView.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Common ancestor of color controls that use `ColorPickerThumbView`. +/// +/// - Important: It is **not** recomended to subclass this class directly. Subclass `ColorPaletteControl` or `ColorSliderControl` instead. +open class ColorControlWithThumbView: AdjustedHitBoxColorControl, LimitedGestureViewDelegate { + public let thumbView = ColorPickerThumbView() + + open override func commonInit() { + super.commonInit() + thumbView.delegate = self + } + + /// Override point. It is called every time the touch is detected in new location. The `thumbView` should be moved and changed accordingly. + /// + /// - Parameter point: New location for the thumb view in coordinate space of the content (adjusted for hitBoxInsets) - that is in coordinate space of `contentView`. + /// - Parameter isInteractive: Whether the change originated from user interaction or is programatic. This can be used to determine if certain animations should be played. + open func updateSelectedColor(at point: CGPoint, isInteractive: Bool = true) { + } + + /// Updates border color of the thumb view when interface is changed to dark or light mode. + open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + thumbView.setDarkBorderIfNeeded(animated: false) + } + + open override func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard let location = locationForTouches(touches) else { + return + } + thumbView.setExpanded(true, animated: true) + updateSelectedColor(at: location) + super.touchesBegan(touches, with: event) + } + + open override func touchesMoved(_ touches: Set, with event: UIEvent?) { + guard let location = locationForTouches(touches) else { + return + } + updateSelectedColor(at: location) + super.touchesMoved(touches, with: event) + } + + open override func touchesEnded(_ touches: Set, with event: UIEvent?) { + guard let location = locationForTouches(touches) else { + return + } + updateSelectedColor(at: location) + thumbView.setExpanded(false, animated: true) + super.touchesEnded(touches, with: event) + } + + open override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + guard let location = locationForTouches(touches) else { + return + } + updateSelectedColor(at: location) + thumbView.setExpanded(false, animated: true) + super.touchesCancelled(touches, with: event) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/PaletteControls.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/PaletteControls.swift new file mode 100644 index 0000000..c5f51bb --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Controls/PaletteControls.swift @@ -0,0 +1,87 @@ +// +// PaletteControls.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 7/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Circular palette color control that allows to change both hue and saturation of current color by selecting a point on the palette. +public class RadialPaletteControl: ColorPaletteControl { + public override func commonInit() { + paletteDelegate = RadialHSBPaletteDelegate() + super.commonInit() + } +} + +/// Rectangle shaped palette color control that allows to change both hue and saturation of current color by selecting a point on the palette. +public class RectangularPaletteControl: ColorPaletteControl { + public override func commonInit() { + paletteDelegate = RectangularHSBPaletteDelegate() + updateBorder(visible: borderOn, view: contentView) + setHue(horizontalAxis: hueHorizontal, updateImage: false) + super.commonInit() + } + + /// When `true`, different values of color hue will correspond to different coordinates along x axis (that means that vertical lines will have same hue but different saturation). When `false`, different values of color hue will correspond to different coordinates along y axis. + /// - Important: Do not set this property from code. It is only intended to be set from interface builder. Call `setHue(horizontalAxis: updateImage:)` instead. + @IBInspectable + public var hueHorizontal: Bool = true { + didSet { + if oldValue != hueHorizontal { + setHue(horizontalAxis: hueHorizontal, updateImage: true) + } + } + } + + /// Whether to display thin border around the palette. + @IBInspectable + public var borderOn: Bool = true { + didSet { + updateBorder(visible: borderOn, view: contentView) + } + } + + /// Sets the value of `hueHorizontal` property. + /// - Note: This operation can be computationally expensive if `updateImage` parameter is `true`. + /// - Parameters: + /// - horizontalAxis: New value for `hueHorizontal` property. + /// - updateImage: When `true`, new palete preview images will be created by palette delegate. This can be computationally expensive. Pass `false` if further updates are expecetd e.g. change of bounds of the color control. + open func setHue(horizontalAxis: Bool, updateImage: Bool) { + hueHorizontal = horizontalAxis + (paletteDelegate as? RectangularHSBPaletteDelegate)?.hueHorizontal = horizontalAxis + if updateImage { + updatePaletteImagesAndThumb(isInteractive: false) + } + } + + /// Updates border color of the rectangular palette control when interface is changed to dark or light mode. + open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + if #available(iOS 13.0, *), traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle { + updateBorder(visible: borderOn, view: contentView) + } + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/CustomColorPickerViewController.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/CustomColorPickerViewController.swift new file mode 100644 index 0000000..5074b95 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/CustomColorPickerViewController.swift @@ -0,0 +1,170 @@ +// +// FlexColorPickerController.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 27/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Customizable color picker view controller that can be subclassed or used from interface builder (or both). This class basically just delegates its exposed properties to wrapped `ColorPickerController`. It is convinience to support common practise that uses view controllers to attach outlets to. +/// +/// When color controls are set to properties of this view controller via code or interface builder, they become managed by underlaying instance of `ColorPickerController` and thus their value (selected color) is synchronized. +/// +/// **See also:** +/// [DefaultColorPickerViewController](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/DefaultColorPickerViewController.swift), [ColorPickerController](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/ColorPickerController.swift) +open class CustomColorPickerViewController: UIViewController, ColorPickerControllerProtocol { + + /// Color picker controller that synchonizes color controls. This is backing controller that this controller delegates interaction logic to. It is also instance of `ColorPickerController` passed to delegate calls. + public let colorPicker = ColorPickerController() + + /// Color picker delegate that gets called when selected color is updated or confirmed. The delegate is not retained. This is just convinience property and getting or setting it is equivalent to getting or setting `colorPicker.delegate`. + open var delegate: ColorPickerDelegate? { + get { + return colorPicker.delegate + } + set { + colorPicker.delegate = newValue + } + } + + /// Color currently selected by color picker. + @IBInspectable + open var selectedColor: UIColor { + get { + return colorPicker.selectedColor + } + set { + colorPicker.selectedColor = newValue + } + } + + @IBOutlet public var colorPreview: ColorPreviewWithHex? { + get { + return colorPicker.colorPreview + } + set { + colorPicker.colorPreview = newValue + } + } + + @IBOutlet open var radialHsbPalette: RadialPaletteControl? { + get { + return colorPicker.radialHsbPalette + } + set { + colorPicker.radialHsbPalette = newValue + } + } + + @IBOutlet open var rectangularHsbPalette: RectangularPaletteControl? { + get { + return colorPicker.rectangularHsbPalette + } + set { + colorPicker.rectangularHsbPalette = newValue + } + } + + @IBOutlet open var saturationSlider: SaturationSliderControl? { + get { + return colorPicker.saturationSlider + } + set { + colorPicker.saturationSlider = newValue + } + } + + @IBOutlet open var brightnessSlider: BrightnessSliderControl? { + get { + return colorPicker.brightnessSlider + } + set { + colorPicker.brightnessSlider = newValue + } + } + + @IBOutlet open var redSlider: RedSliderControl? { + get { + return colorPicker.redSlider + } + set { + colorPicker.redSlider = newValue + } + } + + @IBOutlet open var greenSlider: GreenSliderControl? { + get { + return colorPicker.greenSlider + } + set { + colorPicker.greenSlider = newValue + } + } + + @IBOutlet open var blueSlider: BlueSliderControl? { + get { + return colorPicker.blueSlider + } + set { + colorPicker.blueSlider = newValue + } + } + + @IBOutlet open var customControl1: AbstractColorControl? { + get { + return colorPicker.customControl1 + } + set { + colorPicker.customControl1 = newValue + } + } + + @IBOutlet open var customControl2: AbstractColorControl? { + get { + return colorPicker.customControl2 + } + set { + colorPicker.customControl2 = newValue + } + } + + @IBOutlet open var customControl3: AbstractColorControl? { + get { + return colorPicker.customControl3 + } + set { + colorPicker.customControl3 = newValue + } + } + + open override func viewDidLoad() { + if #available(iOS 13.0, *) { + view.backgroundColor = .systemBackground + } else { + view.backgroundColor = .white + } + super.viewDidLoad() + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/DefaultColorPickerViewController.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/DefaultColorPickerViewController.swift new file mode 100644 index 0000000..e4eee63 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/DefaultColorPickerViewController.swift @@ -0,0 +1,257 @@ +// +// DefaultColorPickerViewController.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 7/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +private let sideMargin: CGFloat = 20 +private let topMargin: CGFloat = 24 +private let paletteVerticalMargin: CGFloat = 42 +private let paletteHorizontalMargin: CGFloat = 32 +private let minDistanceFromSafeArea: CGFloat = 10 +private let minSpaceAboveSlider: CGFloat = 50 + +/// Color picker view controller with predefined layout and limited customisation options. It is designed to be easy to use. You can customize it from interface builder (e.g. you can choose radial or rectangular palette) or from code by setting its properties or directly setting properties of its `colorPalette`, `colorPreview` & `brightnessSlider`. If you need more customisation please use `CustomColorPickerViewController`. +/// +/// **See also:** +/// [CustomColorPickerViewController](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/CustomColorPickerViewController.swift), [ColorPickerController](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/ColorPickerController.swift) +open class DefaultColorPickerViewController: UIViewController, ColorPickerControllerProtocol { + private var standardConstraints = [NSLayoutConstraint]() + private var landscapeConstraints = [NSLayoutConstraint]() + + /// Color picker controller that synchonizes color controls. This is controller that this controller delegates interaction logic to. It is also instance of `ColorPickerController` passed to delegate calls. + public let colorPicker = ColorPickerController() + public let colorPreview = ColorPreviewWithHex() + public let brightnessSlider = BrightnessSliderControl() + private(set) public var colorPalette: ColorPaletteControl = RadialPaletteControl() + + /// Color currently selected by color the picker. + @IBInspectable + open var selectedColor: UIColor { + get { + return colorPicker.selectedColor + } + set { + colorPicker.selectedColor = newValue + } + } + + /// Determines if radial or rectangular color palette will be used. This property is checked only during `viewDidLoad()` and later changes have no effect. If you set this in your `viewDidLoad()` override, call `super.viewDidLoad()` only after you have set this property. Also works with interface builder. + @IBInspectable + open var useRadialPalette: Bool = true + + /// If `useRadialPalette` is `true` then this property specifies whether hue color component is changed with x (`true`) or y axis (`false`) of the color palette. + /// + /// Only applied in potrait orientation on iPhone devices and in all iPad orientations. + @IBInspectable + open var rectangularPaletteHueHorizontalInPortrait: Bool = false { + didSet { + updateLayout(for: view.bounds.size) + } + } + + /// If `useRadialPalette` is `true` then this property specifies whether hue color component is changed with x (`true`) or y axis (`false`) of the color palette. + /// + /// Only applied in landscape orientation on iPhone devices. + @IBInspectable + open var rectangularPaletteHueHorizontalInLandscape: Bool = true { + didSet { + updateLayout(for: view.bounds.size) + } + } + + /// If `useRadialPalette` is `true` then this specifies whether `colorPalette` has border. + @IBInspectable + open var rectangularPaletteBorderOn: Bool = true { + didSet { + (colorPalette as? RectangularPaletteControl)?.borderOn = rectangularPaletteBorderOn + } + } + + /// When `true` the brightness slider label shows 100% for the left-most possition of the slider thumb and 0% for right-most possition. Default is `false` (0% is displayed on left). + /// + /// This is usefull when "physically correct" percentage label behaviour of `BrightnessSliderControl` is preffered (as the most "bright" color is on the left of the slider). However, default value corresponds to the behaviour most users expect. + @IBInspectable + public var reverseBrightnessPercentage: Bool { + get { + return brightnessSlider.reversePercentage + } + set { + brightnessSlider.reversePercentage = newValue + } + } + + /// Color picker delegate that gets called when selected color is updated or confirmed. The delegate is not retained. This is just convinience property and getting or setting it is equivalent to getting or setting `colorPicker.delegate`. + open var delegate: ColorPickerDelegate? { + get { + return colorPicker.delegate + } + set { + colorPicker.delegate = newValue + } + } + + open override func viewDidLoad() { + if #available(iOS 13.0, *) { + view.backgroundColor = .systemBackground + } else { + view.backgroundColor = .white + } + super.viewDidLoad() + + addColorControls() + updateLayout(for: view.bounds.size) + } + + open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + coordinator.animate(alongsideTransition: { _ in + self.updateLayout(for: size) + }, completion: nil) + } + + /// This method sets up and lays out `colorPreview`, `brightnessSlider` and `colorPalette`. It also applies initial values of properties like `useRadialPalette` on them. + /// + /// You can override this method to create your own default layout. + open func addColorControls() { + colorPreview.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(colorPreview) + + colorPicker.colorPreview = colorPreview + + brightnessSlider.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(brightnessSlider) + + + brightnessSlider.hitBoxInsets = UIEdgeInsets(top: defaultHitBoxInset, left: sideMargin, bottom: defaultHitBoxInset, right: sideMargin) + colorPicker.brightnessSlider = brightnessSlider + + if !useRadialPalette { + colorPalette = RectangularPaletteControl() + colorPicker.rectangularHsbPalette = colorPalette as? RectangularPaletteControl + } + else { + colorPicker.radialHsbPalette = colorPalette as? RadialPaletteControl + } + (colorPalette as? RectangularPaletteControl)?.borderOn = rectangularPaletteBorderOn + colorPalette.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(colorPalette) + + colorPalette.contentMode = .top + colorPalette.hitBoxInsets = UIEdgeInsets(top: defaultHitBoxInset, left: sideMargin, bottom: defaultHitBoxInset, right: sideMargin) + + makeStandardLayout() + makeLandscapeLayout() + } + + private func makeStandardLayout() { + standardConstraints += [ + colorPreview.leftAnchor.constraint(equalTo: view.safeAreaLeftAnchor, constant: sideMargin), + colorPreview.topAnchor.constraint(equalTo: view.safeAreaTopAnchor, constant: topMargin), + colorPreview.heightAnchor.constraint(equalToConstant: colorPreview.intrinsicContentSize.height) + ] + colorPreview.setContentCompressionResistancePriority(.init(900), for: .horizontal) + standardConstraints += [ + brightnessSlider.leftAnchor.constraint(equalTo: colorPreview.rightAnchor, constant: sideMargin), + brightnessSlider.rightAnchor.constraint(equalTo: view.safeAreaRightAnchor, constant: -sideMargin), + brightnessSlider.bottomAnchor.constraint(equalTo: colorPreview.bottomAnchor, constant: 0) + ] + standardConstraints += [ + colorPalette.leftAnchor.constraint(equalTo: view.safeAreaLeftAnchor, constant: sideMargin), + colorPalette.rightAnchor.constraint(equalTo: view.safeAreaRightAnchor, constant: -sideMargin), + colorPalette.topAnchor.constraint(equalTo: colorPreview.bottomAnchor, constant: paletteVerticalMargin), + colorPalette.bottomAnchor.constraint(equalTo: view.safeAreaBottomAnchor, constant: -sideMargin) + ] + } + + private func makeLandscapeLayout() { + landscapeConstraints += [ + colorPreview.centerXAnchor.constraint(equalTo: brightnessSlider.centerXAnchor), + colorPreview.bottomAnchor.constraint(equalTo: colorPalette.centerYAnchor, constant: -minSpaceAboveSlider * 0.25) + ] + landscapeConstraints += [ + brightnessSlider.leftAnchor.constraint(equalTo: view.safeAreaLeftAnchor, constant: sideMargin), + brightnessSlider.topAnchor.constraint(equalTo: colorPalette.centerYAnchor, constant: minSpaceAboveSlider * 0.75), + brightnessSlider.rightAnchor.constraint(equalTo: view.centerXAnchor, constant: -paletteHorizontalMargin / 2) + ] + let nonRequiredConstraint = colorPalette.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -sideMargin) + landscapeConstraints += [ + colorPalette.leftAnchor.constraint(equalTo: view.centerXAnchor, constant: paletteHorizontalMargin / 2), + colorPalette.rightAnchor.constraint(equalTo: view.safeAreaRightAnchor, constant: -sideMargin), + colorPalette.topAnchor.constraint(equalTo: view.safeAreaTopAnchor, constant: sideMargin), + nonRequiredConstraint, + colorPalette.bottomAnchor.constraint(lessThanOrEqualTo: view.safeAreaBottomAnchor, constant: -minDistanceFromSafeArea) + ] + nonRequiredConstraint.priority = .init(999) + } + + private func updateLayout(for size: CGSize) { + if size == .zero || standardConstraints.isEmpty || landscapeConstraints.isEmpty { + return + } + let rectangularPalette = (colorPalette as? RectangularPaletteControl) + if size.height < size.width && traitCollection.verticalSizeClass != .regular { + rectangularPalette?.setHue(horizontalAxis: rectangularPaletteHueHorizontalInLandscape, updateImage: false) //image gets updated on bounds change + NSLayoutConstraint.deactivate(standardConstraints) + NSLayoutConstraint.activate(landscapeConstraints) + return + } + + rectangularPalette?.setHue(horizontalAxis: rectangularPaletteHueHorizontalInPortrait, updateImage: false) //image gets updated on bounds change + NSLayoutConstraint.deactivate(landscapeConstraints) + NSLayoutConstraint.activate(standardConstraints) + } +} + +fileprivate extension UIView { + var safeAreaLeftAnchor: NSLayoutXAxisAnchor { + if #available(iOS 11.0, *) { + return safeAreaLayoutGuide.leftAnchor + } + return leftAnchor + } + + var safeAreaRightAnchor: NSLayoutXAxisAnchor { + if #available(iOS 11.0, *) { + return safeAreaLayoutGuide.rightAnchor + } + return rightAnchor + } + + var safeAreaBottomAnchor: NSLayoutYAxisAnchor { + if #available(iOS 11.0, *) { + return safeAreaLayoutGuide.bottomAnchor + } + return topAnchor + } + + var safeAreaTopAnchor: NSLayoutYAxisAnchor { + if #available(iOS 11.0, *) { + return safeAreaLayoutGuide.topAnchor + } + return topAnchor + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/FlexColorPicker.h b/Pods/FlexColorPicker/FlexColorPicker/Classes/FlexColorPicker.h new file mode 100644 index 0000000..bf9e251 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/FlexColorPicker.h @@ -0,0 +1,19 @@ +// +// FlexColorPicker.h +// FlexColorPicker +// +// Created by Rastislav Mirek on 27/5/18. +// Copyright © 2018 TypeSoft. All rights reserved. +// + +#import + +//! Project version number for FlexColorPicker. +FOUNDATION_EXPORT double FlexColorPickerVersionNumber; + +//! Project version string for FlexColorPicker. +FOUNDATION_EXPORT const unsigned char FlexColorPickerVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/HSBColor.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/HSBColor.swift new file mode 100644 index 0000000..470fb17 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/HSBColor.swift @@ -0,0 +1,165 @@ +// +// HSLColor.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 29/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Represetation of a color in HSB (Hue, Saturation, Brightness) color model. This model can be directly converted to and from RGB model. +/// - Note: HSB is better representation for color picker than RGB as its components often maps directly to user interactions. +public struct HSBColor { + /// Hue value in interval <0, 1> + public let hue: CGFloat + /// Saturation value in interval <0, 1> + public let saturation: CGFloat + /// Brightness value in interval <0, 1> + public let brightness: CGFloat + /// Alpha value in interval <0, 1> + public let alpha: CGFloat + + public init(hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat = 1) { + self.hue = max(0, min(1, hue)) + self.saturation = max(0, min(1, saturation)) + self.brightness = max(0, min(1, brightness)) + self.alpha = max(0, min(1, alpha)) + } +} + +extension HSBColor { + + /// RGB representation of this HSBColor + var rgb: (red: CGFloat, green: CGFloat, blue: CGFloat) { + return rgbFrom(hue: hue, saturation: saturation, brightness: brightness) + } + + /// Initializes `HSBColor` instance that represents the same color as passed color. + /// + /// - Parameter color: A color to construct an equivalent `HSBColor` from. + init(color: UIColor) { + var hue: CGFloat = 0, saturation: CGFloat = 0, brightness: CGFloat = 0, alpha: CGFloat = 0 + color.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) + self.init(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } + + public func asTuple() -> (hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat) { + return (hue, saturation, brightness, alpha) + } + + public func asTupleNoAlpha() -> (hue: CGFloat, saturation: CGFloat, brightness: CGFloat) { + return (hue, saturation, brightness) + } + + + /// Returs `UIColor` that represents equivalent color as this instance. + /// + /// - Returns: `UIColor` equivalent to this `HSBColor`. + public func toUIColor() -> UIColor { + return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } + + public func withHue(_ hue: CGFloat, andSaturation saturation: CGFloat) -> HSBColor { + return HSBColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } + + public func withSaturation(_ saturation: CGFloat, andBrightness brightness: CGFloat) -> HSBColor { + return HSBColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } + + public func withHue(_ hue: CGFloat, andBrightness brightness: CGFloat) -> HSBColor { + return HSBColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } + + public func withHue(_ hue: CGFloat) -> HSBColor { + return HSBColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } + + public func withSaturation(_ saturation: CGFloat) -> HSBColor { + return HSBColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } + + public func withBrightness(_ brightness: CGFloat) -> HSBColor { + return HSBColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } + + /// Computes new HSL color based on given RGB values while keeping alpha value of original color. + /// - Note: If the RGB values given specify achromatic color the hue of original color is kept. + /// - Parameter red: Red component of new color specified as value from <0, 1> + /// - Parameter green: Green component of new color specified as value from <0, 1> + /// - Parameter blue: Blue component of new color specified as value from <0, 1> + /// - Returns: Color specified by the given RGB values with the same alpha as current color. + public func withRGB(red: CGFloat, green: CGFloat, blue: CGFloat) -> HSBColor { + let red_ = min(1, max(0, red)) + let green_ = min(1, max(0, green)) + let blue_ = min(1, max(0, blue)) + + let max_ = fmax (red_, fmax(green_, blue_)) + let min_ = fmin(red_, fmin(green_, blue_)) + + var h: CGFloat = 0, b = max_ + let d = max_ - min_ + let s = max_ == 0 ? 0 : d / max_ + + guard max_ != min_ else { + return HSBColor(hue: hue, saturation: 1 - max_, brightness: b, alpha: alpha) //achromatic: keep the original hue (that is why this is an extension) + } + if max_ == red_ { + h = (green_ - blue) / d + (green_ < blue_ ? 6 : 0) + } + else if max_ == green_ { + h = (blue_ - red_) / d + 2 + } + else if max_ == blue_ { + h = (red_ - green_) / d + 4 + } + h /= 6 + return HSBColor(hue: h, saturation: s, brightness: b, alpha: alpha) + } + + public func withRed(_ red: CGFloat) -> HSBColor { + let (_, g, b) = rgb + return withRGB(red: red, green: g, blue: b) + } + + public func withGreen(_ green: CGFloat) -> HSBColor { + let (r, _, b) = rgb + return withRGB(red: r, green: green, blue: b) + } + + public func withBlue(_ blue: CGFloat) -> HSBColor { + let (r, g, _) = rgb + return withRGB(red: r, green: g, blue: blue) + } + + public func withAlpha(_ alpha: CGFloat) -> HSBColor { + return HSBColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha) + } +} + +extension HSBColor: Hashable { + public static func == (l: HSBColor, r: HSBColor) -> Bool { + return l.hue == r.hue && l.saturation == r.saturation && l.brightness == r.brightness && l.alpha == r.alpha + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/CGPointExtension.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/CGPointExtension.swift new file mode 100644 index 0000000..65b615b --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/CGPointExtension.swift @@ -0,0 +1,41 @@ +// +// CGPointExtension.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 27/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +extension CGPoint { + func distanceTo(x: CGFloat, y: CGFloat) -> CGFloat { + let dx = self.x - x + let dy = self.y - y + return sqrt(dx * dx + dy * dy) + } + + func distance(to point: CGPoint) -> CGFloat { + return distanceTo(x: point.x, y: point.y) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/CGRectExtension.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/CGRectExtension.swift new file mode 100644 index 0000000..b862218 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/CGRectExtension.swift @@ -0,0 +1,35 @@ +// +// CGRectExtension.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +extension CGRect { + init(center: CGPoint, size: CGSize) { + self.init(origin: CGPoint(x: center.x - size.width / 2, y: center.y - size.height / 2), size: size) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/LimitedGestureViewDelegate.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/LimitedGestureViewDelegate.swift new file mode 100644 index 0000000..d33fbe8 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/LimitedGestureViewDelegate.swift @@ -0,0 +1,33 @@ +// +// LimitedGestureViewDelegate.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 29/9/19. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +public protocol LimitedGestureViewDelegate: AnyObject { + func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIColorExtension.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIColorExtension.swift new file mode 100644 index 0000000..ecbb4a7 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIColorExtension.swift @@ -0,0 +1,140 @@ +// +// UIColorExtensions.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 27/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +extension UIColor { + var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 + getRed(&red, green: &green, blue: &blue, alpha: &alpha) + return (red, green, blue, alpha) + } + + var rgb: (red: CGFloat, green: CGFloat, blue: CGFloat) { + let (red, green, blue, _) = rgba + return (red, green, blue) + } + + // neither of the following computed static properties can be made stored property - their current values need to computed at the time of accesing them + public static var colorPickerBorderColor: UIColor { + return pickColorForMode(lightModeColor: #colorLiteral(red: 0.7089999914, green: 0.7089999914, blue: 0.7089999914, alpha: 1), darkModeColor: #colorLiteral(red: 0.4203212857, green: 0.4203212857, blue: 0.4203212857, alpha: 1)) + } + + public static var colorPickerLabelTextColor: UIColor { + return pickColorForMode(lightModeColor: #colorLiteral(red: 0.5, green: 0.5, blue: 0.5, alpha: 1), darkModeColor: #colorLiteral(red: 0.6395837665, green: 0.6395837665, blue: 0.6395837665, alpha: 1)) + } + + public static var colorPickerLightBorderColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.200000003) + public static var colorPickerThumbViewWideBorderColor: UIColor { + return pickColorForMode(lightModeColor: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.6999999881), darkModeColor: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.5995928578)) + } + + public static var colorPickerThumbViewWideBorderDarkColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.3000000119) + + public var hsbColor: HSBColor { + return HSBColor(color: self) + } + + public func hexValue(alwaysIncludeAlpha: Bool = false) -> String { + let (red, green, blue, alpha) = rgba + let r = colorComponentToUInt8(red) + let g = colorComponentToUInt8(green) + let b = colorComponentToUInt8(blue) + let a = colorComponentToUInt8(alpha) + + if alpha == 1 && !alwaysIncludeAlpha { + return String(format: "%02lX%02lX%02lX", r, g, b) + } + return String(format: "%02lX%02lX%02lX%02lX", r, g, b, a) + } + + /// Computes contrast ratio between this color and given color as a value from interval <0, 1> where 0 is contrast ratio of the same colors and 1 is contrast ratio between black and white. + func constrastRatio(with color: UIColor) -> CGFloat { + let (r1, g1, b1) = rgb + let (r2, g2, b2) = color.rgb + + return (abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2)) / 3 + } +} + +private func pickColorForMode(lightModeColor: UIColor, darkModeColor: UIColor) -> UIColor { + if #available(iOS 13, *) { + return UIColor { (UITraitCollection: UITraitCollection) -> UIColor in + UITraitCollection.userInterfaceStyle == .dark ? darkModeColor : lightModeColor + } + } + return lightModeColor +} + +@inline(__always) +public func colorComponentToUInt8(_ component: CGFloat) -> UInt8 { + return UInt8(max(0, min(255, round(255 * component)))) +} + +/// Translates color from HSB system to RGB, given constant Brightness value of 1. +/// @param hue Hue value in range from 0 to 1 (inclusive). +/// @param saturation Saturation value in range from 0 to 1 (inclusive). +/// @param brightness Brightness value in range from 0 to 1 (inclusive). +public func rgbFrom(hue: CGFloat, saturation: CGFloat, brightness: CGFloat) -> (red: CGFloat, green: CGFloat, blue: CGFloat) { + let hPrime = Int(hue * 6) + let f = hue * 6 - CGFloat(hPrime) + let p = brightness * (1 - saturation) + let q = brightness * (1 - f * saturation) + let t = brightness * (1 - (1 - f) * saturation) + + switch hPrime % 6 { + case 0: return (brightness, t, p) + case 1: return (q, brightness, p) + case 2: return (p, brightness, t) + case 3: return (p, q, brightness) + case 4: return (t, p, brightness) + default: return (brightness, p, q) + } +} + +//code currently not used but might consider publishing it in the future as a color utilities - leaving here for reference +extension UIColor { + // public var alpha: CGFloat { + // return rgba.alpha + // } + // + // public func withRed(_ red: CGFloat) -> UIColor { + // let (_, g, b, a) = self.rgba + // return UIColor(red: red, green: g, blue: b, alpha: a) + // } + // + // public func withGreen(_ green: CGFloat) -> UIColor { + // let (r, _ , b, a) = self.rgba + // return UIColor(red: r, green: green, blue: b, alpha: a) + // } + // + // public func withBlue(_ blue: CGFloat) -> UIColor { + // let (r, g, _, a) = self.rgba + // return UIColor(red: r, green: g, blue: blue, alpha: a) + // } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIImageExtension.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIImageExtension.swift new file mode 100644 index 0000000..2ea54c5 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIImageExtension.swift @@ -0,0 +1,57 @@ +// +// UIImageExtension.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 2/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +extension UIImage { + public convenience init?(rgbaBytes: [UInt8], width: Int, height: Int) { + let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue) + let data = Data(rgbaBytes) + let mutableData = UnsafeMutableRawPointer.init(mutating: (data as NSData).bytes) + let context = CGContext(data: mutableData, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4 * width, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: bitmapInfo.rawValue) + guard let cgImage = context?.makeImage() else { + return nil + } + self.init(cgImage: cgImage) + } + + public static func drawImage(ofSize size: CGSize, path: UIBezierPath, fillColor: UIColor) -> UIImage? { + UIGraphicsBeginImageContextWithOptions(size, false, 0) + let context = UIGraphicsGetCurrentContext() + context?.setFillColor(fillColor.cgColor) + context?.addPath(path.cgPath) + context?.drawPath(using: .fill) + defer { + UIGraphicsEndImageContext() + } + if let image = UIGraphicsGetImageFromCurrentImageContext() { + return image + } + return nil + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIImageViewExtension.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIImageViewExtension.swift new file mode 100644 index 0000000..d84815e --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIImageViewExtension.swift @@ -0,0 +1,85 @@ + +// +// UIImageViewExtension.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 4/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +extension UIImageView { + func convertToImageSpace(point: CGPoint) -> CGPoint { + return transform(point: point, toImageSpace: true) + } + + func convertFromImageSpace(point: CGPoint) -> CGPoint { + return transform(point: point, toImageSpace: false) + } + + private func transform(point: CGPoint, toImageSpace: Bool) -> CGPoint { + guard let contentSize = image?.size else { + return point + } + let multiplier: CGFloat = toImageSpace ? -1 : 1 + let verticalDiff = (bounds.height - contentSize.height) * multiplier + let horizontalDiff = (bounds.width - contentSize.width) * multiplier + return CGPoint( + x: adjustedCoordinate(for: point.x, axisAlignment: contentMode.horizontalAlighnment, difference: horizontalDiff), + y: adjustedCoordinate(for: point.y, axisAlignment: contentMode.verticalAlighnment, difference: verticalDiff) + ) + } + + private func adjustedCoordinate(for coordinate: CGFloat, axisAlignment: Alighnment, difference: CGFloat) -> CGFloat { + switch axisAlignment { + case .begining: return coordinate + case .center: return coordinate + difference / 2 + case .end: return coordinate + difference + } + } +} + +private enum Alighnment { + case begining, center, end +} + +fileprivate extension UIView.ContentMode { + var verticalAlighnment: Alighnment { + switch self { + case .bottom, .bottomLeft, .bottomRight: return .end + case .center, .left, .right, .scaleAspectFit, .scaleAspectFill, .scaleToFill, .redraw: return .center + case .top, .topRight, .topLeft: return .begining + @unknown default: return .center + } + } + + var horizontalAlighnment: Alighnment { + switch self { + case .left, .topLeft, .bottomLeft: return .begining + case .top, .center, .bottom, .scaleAspectFit, .scaleAspectFill, .scaleToFill, .redraw: return .center + case .right, .topRight, .bottomRight: return .end + @unknown default: return .center + } + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIViewExtension.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIViewExtension.swift new file mode 100644 index 0000000..4e4fc19 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Utilities/UIViewExtension.swift @@ -0,0 +1,80 @@ +// +// UIViewExtension.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 27/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +extension UIView { + func addAutolayoutFillingSubview(_ subview: UIView, edgeInsets: UIEdgeInsets = .zero) { + subview.translatesAutoresizingMaskIntoConstraints = false + addSubview(subview) + + subview.leftAnchor.constraint(equalTo: leftAnchor, constant: edgeInsets.left).isActive = true + subview.topAnchor.constraint(equalTo: topAnchor, constant: edgeInsets.top).isActive = true + subview.rightAnchor.constraint(equalTo: rightAnchor, constant: -edgeInsets.right).isActive = true + subview.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -edgeInsets.bottom).isActive = true + } + + func addAutolayoutCentredView(_ subview: UIView, offset: CGSize = .zero) { + subview.translatesAutoresizingMaskIntoConstraints = false + addSubview(subview) + + subview.centerXAnchor.constraint(equalTo: centerXAnchor, constant: offset.width).isActive = true + subview.centerYAnchor.constraint(equalTo: centerYAnchor, constant: offset.height).isActive = true + } + + var borderWidth: CGFloat { + get { + return layer.borderWidth + } + set { + layer.borderWidth = newValue + } + } + + var viewBorderColor: UIColor? { + get { + if let cgColor = layer.borderColor { + return UIColor(cgColor: cgColor) + } + return nil + } + set { + layer.borderColor = newValue?.cgColor + } + } + + @objc + var cornerRadius_: CGFloat { + get { + return layer.cornerRadius + } + set { + layer.cornerRadius = newValue + } + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/CircleShapedView.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/CircleShapedView.swift new file mode 100644 index 0000000..a16376c --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/CircleShapedView.swift @@ -0,0 +1,47 @@ +// +// CircleShapedView.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// A view with shaped into circle by setting corner radius. +open class CircleShapedView: UIViewWithCommonInit { + public override var bounds: CGRect { + didSet { + updateCornerRadius() + } + } + + open override func commonInit() { + super.commonInit() + updateCornerRadius() + } + + private func updateCornerRadius() { + cornerRadius_ = min(bounds.height, bounds.width) / 2 + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/ColorControlContentView.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/ColorControlContentView.swift new file mode 100644 index 0000000..787dddb --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/ColorControlContentView.swift @@ -0,0 +1,45 @@ +// +// ColorControlContentView.swift +// Pods +// +// Created by Rastislav Mirek on 25/9/19. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +protocol ColorControlContentViewDelegate: AnyObject { + func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool +} + +/// Content holder for all color controls derived from `AbstractColorControl`. Delegates its `gestureRecognizerShouldBegin(:)` method to settable delegate. Use it as a regular `UIView`. +class ColorControlContentView: UIView { + weak var delegate: ColorControlContentViewDelegate? + + override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + if let delegate = delegate { + return delegate.gestureRecognizerShouldBegin(gestureRecognizer) + } + return true + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/ColorPickerThumbView.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/ColorPickerThumbView.swift new file mode 100644 index 0000000..9cbaa32 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/ColorPickerThumbView.swift @@ -0,0 +1,169 @@ +// +// ColorPickerThumbView.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +private let colorPickerThumbViewDiameter: CGFloat = 28 +private let defaultWideBorderWidth: CGFloat = 6 +private let defaultExpandedUpscaleRatio: CGFloat = 1.6 +private let expansionAnimationDuration = 0.3 +private let collapsingAnimationDelay = 0.1 +private let borderDarkeningAnimationDuration = 0.3 +private let expansionAnimationSpringDamping: CGFloat = 0.7 +private let brightnessToChangeToDark: CGFloat = 0.3 +private let saturationToChangeToDark: CGFloat = 0.4 +private let textLabelUpShift: CGFloat = 12 +private let maxContrastRatioWithWhiteToDarken: CGFloat = 0.25 +private let percentageTextFont = UIFont.monospacedDigitSystemFont(ofSize: 14, weight: .regular) + +@IBDesignable +open class ColorPickerThumbView: UIViewWithCommonInit { + public let borderView: CircleShapedView = LimitedGestureCircleView() + public let colorView: CircleShapedView = LimitedGestureCircleView() + /// The label with thumb text visible while user is repositioning this thumbView. + /// + /// Typically used to show slider percentage or other selected value. See also `showPercentage`. + public let percentageLabel = UILabel() + /// When `true` the border automatically darken when color is too bright to be contrast enought with white border. + public var autoDarken: Bool = true + /// Whether to show percentage label above the thumb view. + public var showPercentage: Bool = true + /// Whether the thumb view should be expanded when user is interacting with it. + public var expandOnTap: Bool = true + var delegate: LimitedGestureViewDelegate? { + didSet { + (borderView as? LimitedGestureCircleView)?.delegate = delegate + (colorView as? LimitedGestureCircleView)?.delegate = delegate + } + } + + var expandedUpscaleRatio: CGFloat = defaultExpandedUpscaleRatio { + didSet { + if isExpanded { + setExpanded(true, animated: true) + } + } + } + private(set) open var color: UIColor = defaultSelectedColor.toUIColor() + + /// The percentage displayed in `percentageLabel` unless overriden by dirrectly setting `percentageLabel.text` after setting this property. + /// + /// Note: In `ColorSliderControl`s this typically corresponds to value of the slider but must not correspond to actual text displayed in `thumbLabel` if `ColorSliderControl.thumbLabelFormatter` is set. + open var percentage: Int = 0 { + didSet { + updatePercentage(percentage) + } + } + + public private(set) var isExpanded = false + + open override var intrinsicContentSize: CGSize { + return CGSize(width: colorPickerThumbViewDiameter, height: colorPickerThumbViewDiameter) + } + + var wideBorderWidth: CGFloat { + return defaultWideBorderWidth + } + + open override func commonInit() { + super.commonInit() + addAutolayoutFillingSubview(borderView) + addAutolayoutFillingSubview(colorView, edgeInsets: UIEdgeInsets(top: wideBorderWidth, left: wideBorderWidth, bottom: wideBorderWidth, right: wideBorderWidth)) + addAutolayoutCentredView(percentageLabel) + borderView.viewBorderColor = UIColor.colorPickerBorderColor + borderView.borderWidth = 1 / UIScreen.main.scale + percentageLabel.font = percentageTextFont + percentageLabel.textColor = UIColor.colorPickerLabelTextColor + percentageLabel.textAlignment = .center + percentageLabel.alpha = 0 + clipsToBounds = false // required for the text label to be displayed ourside of bounds + borderView.backgroundColor = UIColor.colorPickerThumbViewWideBorderColor + (borderView as? LimitedGestureCircleView)?.delegate = delegate + (colorView as? LimitedGestureCircleView)?.delegate = delegate + setColor(color, animateBorderColor: false) + } + + open func setColor(_ color: UIColor, animateBorderColor: Bool) { + self.color = color + colorView.backgroundColor = color + setDarkBorderIfNeeded(animated: animateBorderColor) + } + + public func updatePercentage(_ percentage: Int) { + percentageLabel.text = String(min(100, max(0, percentage))) + "%" + } +} + +extension ColorPickerThumbView { + + open func setExpanded(_ expanded: Bool, animated: Bool) { + let transform = expanded && expandOnTap ? CATransform3DMakeScale(expandedUpscaleRatio, expandedUpscaleRatio, 1) : CATransform3DIdentity + let textLabelRaiseAmount: CGFloat = expanded && expandOnTap ? (bounds.height / 2) * defaultExpandedUpscaleRatio + textLabelUpShift : (bounds.height / 2) + textLabelUpShift + let labelTransform = CATransform3DMakeTranslation(0, -textLabelRaiseAmount, 0) + isExpanded = expanded + + UIView.animate(withDuration: animated ? expansionAnimationDuration : 0, delay: expanded ? 0 : collapsingAnimationDelay, usingSpringWithDamping: expansionAnimationSpringDamping, initialSpringVelocity: 0, options: [], animations: { + self.borderView.layer.transform = transform + self.colorView.layer.transform = transform + self.percentageLabel.layer.transform = labelTransform + self.percentageLabel.alpha = expanded && self.showPercentage ? 1 : 0 + }, completion: nil) + } + + open func setDarkBorderIfNeeded(animated: Bool = true) { + let (_, s, b) = color.hsbColor.asTupleNoAlpha() + let isBorderDark = autoDarken && 1 - b < brightnessToChangeToDark && s < saturationToChangeToDark +// let isBorderDark = autoDarken && color.constrastRatio(with: .white) < maxContrastRatioWithWhiteToDarken + + #if TARGET_INTERFACE_BUILDER + setWideBorderColors(isBorderDark) //animations do not work + #else + UIView.animate(withDuration: animated ? borderDarkeningAnimationDuration : 0) { + self.setWideBorderColors(isBorderDark) + } + #endif + } + + open var colorIdicatorRadius: CGFloat { + return bounds.width / 2 - wideBorderWidth + } + + private func setWideBorderColors(_ isDark: Bool) { + self.borderView.viewBorderColor = isDark ? UIColor.colorPickerBorderColor : UIColor.colorPickerLightBorderColor + self.borderView.backgroundColor = isDark ? UIColor.colorPickerThumbViewWideBorderDarkColor : UIColor.colorPickerThumbViewWideBorderColor + } +} + +extension ColorPickerThumbView { + open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + guard let delegate = (borderView as? LimitedGestureCircleView)?.delegate else { + return !(gestureRecognizer is UIPanGestureRecognizer) + } + return delegate.gestureRecognizerShouldBegin(gestureRecognizer) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/GradientView.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/GradientView.swift new file mode 100644 index 0000000..f5be0cd --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/GradientView.swift @@ -0,0 +1,84 @@ +// +// GradientView.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// View with linear gradient background instead of solid color. +public class GradientView: UIView { + open override class var layerClass: AnyClass { + return CAGradientLayer.self + } + + var gradientLayer: CAGradientLayer { + return layer as! CAGradientLayer + } + + /// Background gradient first color (first stop of the gradient). + public var startColor: UIColor = .clear { + didSet { + updateColors() + } + } + + /// Background gradient last color (last stop of the gradient). + public var endColor: UIColor = .clear { + didSet { + updateColors() + } + } + + /// How far to right the begining of background gradient shoulds be from the view's left edge. In points. + public var startOffset: CGFloat = 0 { + didSet { + updatePoints() + } + } + + /// How far to the left the end of background gradient shoulds be from the view's right edge. In points. + public var endOffset: CGFloat = 0 { + didSet { + updatePoints() + } + } + + public override var bounds: CGRect { + didSet { + updatePoints() + } + } + + open func updateColors() { + gradientLayer.colors = [startColor.cgColor, endColor.cgColor] + } + + open func updatePoints() { + gradientLayer.startPoint = CGPoint(x: startOffset / bounds.width, y: 0.5) + gradientLayer.endPoint.x = 1 - endOffset / bounds.width //some strange bug causes it to asign NaN for x when directly assigning CGPoint + gradientLayer.endPoint.y = 0.5 + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/LimitedGestureCircleView.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/LimitedGestureCircleView.swift new file mode 100644 index 0000000..9fd00eb --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/LimitedGestureCircleView.swift @@ -0,0 +1,41 @@ +// +// NoPanCircleView.swift +// Pods +// +// Created by Rastislav Mirek on 25/9/19. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// Delegates gesture recognition control to its delegate. Use it as CircleShapedView. +class LimitedGestureCircleView: CircleShapedView { + weak var delegate: LimitedGestureViewDelegate? + + override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + guard let delegate = delegate else { + return !(gestureRecognizer is UIPanGestureRecognizer) + } + return delegate.gestureRecognizerShouldBegin(gestureRecognizer) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/PaletteAwareScrollView.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/PaletteAwareScrollView.swift new file mode 100644 index 0000000..fec9009 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/PaletteAwareScrollView.swift @@ -0,0 +1,59 @@ +// +// PaletteAwareScrollView.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 7/6/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +/// A scroll view that supports adding instances of `ColorPaletteControl` in its content without compromising their panning (color selection by dragging a finger) functionality. +/// +/// This scroll view interprets panning over palettes inside its content as a gesture intended for that palette but as scroll gesture. +@available(iOS, deprecated: 1.3, message: "Provided color controls now works correctly when part of any UIScrollView hierarchy so there is no need for PaletteAwareScrollView") +open class PaletteAwareScrollView: UIScrollView { + + open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + if gestureRecognizer !== panGestureRecognizer { + return super.gestureRecognizerShouldBegin(gestureRecognizer) + } + + let touchLocation = gestureRecognizer.location(in: self) + let hitView = hitTest(touchLocation, with: nil) + if isCondition({ $0 is ColorPaletteControl}, satisfiedByParentOf: hitView) { + return false + } + return super.gestureRecognizerShouldBegin(gestureRecognizer) + } + + private func isCondition(_ condition: (UIView) -> Bool, satisfiedByParentOf view: UIView?) -> Bool { + guard let view = view, view !== self else { + return false + } + if condition(view) { + return true + } + return isCondition(condition, satisfiedByParentOf: view.superview) + } +} diff --git a/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/UIViewWithCommonInit.swift b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/UIViewWithCommonInit.swift new file mode 100644 index 0000000..c4b9d96 --- /dev/null +++ b/Pods/FlexColorPicker/FlexColorPicker/Classes/Views/UIViewWithCommonInit.swift @@ -0,0 +1,55 @@ +// +// UIViewWithCommonInit.swift +// FlexColorPicker +// +// Created by Rastislav Mirek on 28/5/18. +// +// MIT License +// Copyright (c) 2018 Rastislav Mirek +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +import UIKit + +open class UIViewWithCommonInit: UIView { + public override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + commonInit() + } + + open override func awakeFromNib() { + super.awakeFromNib() + commonInit() + } + + open override func prepareForInterfaceBuilder() { + super.prepareForInterfaceBuilder() + commonInit() + } + + /// This empty method is override point for initialization tasks that needs to be carried no matter how the view is constructed (e. g. via Interface Builder or from code). + open func commonInit() { + } +} diff --git a/Pods/FlexColorPicker/LICENSE b/Pods/FlexColorPicker/LICENSE new file mode 100644 index 0000000..77e1cb0 --- /dev/null +++ b/Pods/FlexColorPicker/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Rastislav Mirek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Pods/FlexColorPicker/README.md b/Pods/FlexColorPicker/README.md new file mode 100644 index 0000000..1b12fb2 --- /dev/null +++ b/Pods/FlexColorPicker/README.md @@ -0,0 +1,217 @@ +[![Build Status](https://travis-ci.org/RastislavMirek/FlexColorPicker.svg?branch=master)](https://travis-ci.org/RastislavMirek/FlexColorPicker.svg) +[![License Badge](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/RastislavMirek/FlexColorPicker/blob/master/LICENSE) +[![Pod Version Badge](https://img.shields.io/cocoapods/v/FlexColorPicker.svg)](https://cocoapods.org/pods/FlexColorPicker) +![Swift Version Badge](https://img.shields.io/badge/swift-v5-blue.svg) +# Flex Color Picker +Hackable color picker library written in Swift 5 that can be easily extended and customized. It aims to provide great UX and performance with stable, quality code. Includes controls for both HSB and RGB color models. + +![Default Flex Color Picker Preview](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Flex_color_picker_for_swift_preview1.gif) +![Color Picker with All Controls Preview](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Flex_color_picker_for_swift_preview2.gif) + +## Features +- supports [HSB and RGB](#storyboardscreenshot) color models, both [radial and rectangular](#rectangular) hue/saturation palette +- there is [_ready-to-use view controller_](#basic-usage) if you need quick, simple solution +- freely combine, leave out or add your own picker components when you need flexibility +- well documented +- _highly [customisable](#customisation)_ +- _storyboard support_ with [design time preview](#storyboardscreenshot) and customisation directly from storyboard +- library consists of small classes and robust, easy to understand code +- can be used [without subclassing specific controller](#nosubclassing) +- hackable: [_protocols_](#protocols) for adding custom picker controls, open classes ready for subclassing + +![Default Color Picker with Rectangular Palette Preview](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Flex_color_picker_for_swift_preview3.gif) +![Custom Color Picker Controls Written in Swift Preview](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Flex_color_picker_for_swift_preview4.gif) + +## Use Cases +1. [plug & play](#basic-usage) color picker that works great out-of-box +2. [agile library](#available-color-controls) that supports components positioning with autolayout and customisation [directly from storyboard](#connecting-color-controls) +3. framework that allows [adding your own](#extending--overriding) sliders, palettes & previews or modifying [existing ones](#available-color-controls) without changing the code of the library +4. combine 3 approaches above freely to get the level of customisation that you need + +## Instalation + +### Swift Package Manager + +In XCode 11 and above click _File_ → _Swift Packages_ → _Add Package Dependency..._ → choose target to add FlexColorPicker to → enter `https://github.com/RastislavMirek/FlexColorPicker`, press next → set version prefference and confirm. + +Alternativelly, if you are using Package.swift just add this dependency: + + dependencies: [ + .package(url: "https://github.com/RastislavMirek/FlexColorPicker.git", from: "1.3.1") + ] + +### Cocoapods +Add this to your podfile: + + pod 'FlexColorPicker' + +You can also try the Demo project with following command: + + pod try FlexColorPicker + +### Direct Instalation +If you are not Cocoapods or SPM user you can clone the color picker from repository with this command: + + git clone https://github.com/RastislavMirek/FlexColorPicker + +Alternativelly, you can download latest release as ZIP from [releases](https://github.com/RastislavMirek/FlexColorPicker/releases). + +Then open the cloned/downloaded project in XCode and compile target _FlexColorPicker_. File FlexColorPicker.framework will be created in _Products_ directory. Open project that you want to add the color picker to in XCode, select project file, select your application's target on the left side, select _General_ tab and add FlexColorPicker.framework under _Embedded Binaries_ section. + +![Default HSB Color Picker Preview](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Combined_Color_Picker_Preview.jpg) + +## Basic Usage (Plug & Play) + +The fastest and simplest way to add color picker to your project is using `DefaultColorPickerViewController`. You can add it either [via storyboard](#adding-via-storyboard) or [via code](adding-via-code). In both cases you will need to implement [`ColorPickerDelegate` protocol](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/ColorPickerDelegate.swift) to receive update when a user selects color using the `DefaultColorPickerViewController`: + + // MyController is the controller that presents DefaultColorPickerViewController + extension MyController: ColorPickerDelegate { + + func colorPicker(_ colorPicker: ColorPickerController, selectedColor: UIColor, usingControl: ColorControl) { + // code to handle that user selected a color without confirmed it yet (may change selected color) + } + + func colorPicker(_ colorPicker: ColorPickerController, confirmedColor: UIColor, usingControl: ColorControl) { + // code to handle that user has confirmed selected color + } + } + +Both functions in `ColorPickerDelegate` are optional. You can only use one of them or both in conjuncion. + + #### Adding via Storyboard + + In storyboard, FlexColorPicker can be used by specifying _Class_ of a view controller to be `DefaultColorPickerViewController`. That is done in [_Identity Inspector_](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Identity_Inspector.jpg) in right panel under _Custom Class_. Basic customisation of the controller is supported in storyboard via properties in [_Attributes Inspector_](https://www.quora.com/Where-is-an-attributes-inspector-in-Xcode). Delegate of `DefaultColorPickerViewController` can only be set in code: + + class MyController { + @IBOutlet var pickerController: ColorPickerController! + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if let destinationColorPicker = segue.destination as? ColorPickerControllerProtocol { + destinationColorPicker.delegate = self + } + } + } + +#### Adding via Code + +`DefaultColorPickerViewController` can be displayed like this if using a navigation controller: + + let colorPickerController = DefaultColorPickerViewController() + colorPickerController.delegate = self + navigationController?.pushViewController(colorPickerController, animated: true) + +Replace the 3rd line of the above snippet with following code to display color picker modally: + + let navigationController = UINavigationController(rootViewController: colorPickerController) + present(navigationController, animated: true, completion: nil) + +All the above code should go to handler that triggers color picker display (e.g. handler of "Pick Color" button press). + +If preffered, you can use following code to set `DefaultColorPickerViewController` to use rectangular, rather than radial hue-saturation pallete. See third animated image on this page for example. + + colorPickerController.useRadialPalette = false + +You can also set 3 additional properties that influence how color picker looks when rectangular palette is used (`rectangularPaletteBorderOn`, `rectangularPaletteHueHorizontalInPortrait` and `rectangularPaletteHueHorizontalInLandscape`). See [in-code +documentation](#documentation) for details. For more customisation please refer to section [Customisation](#customisation) below. + +## Custom Usage + +`DefaultColorPickerViewController` is plug & play option (see [Basic Usage](#basic-usage--plug--play)) with limited customisation. It is a convinince "ready-to-use" view controller which makes use of FlexColorPicker's _color controls_ and _color picker controllers_. _Color controls_ are `UIView`s that (usually) subclass [`UIControl`](https://developer.apple.com/documentation/uikit/uicontrol) and allow user to pick desired color and _color picker controllers_ manage them. If more flexibility than what `DefaultColorPickerViewController` provides is needed, you can use them dirrectly: + +1. If custom layout of _color controls_ is needed, read [Custom Layout](#custom-layout). +2. If custom look or behavior of color _color controls_ is needed, read [] +3. If both custom layout and behavior/look of _color controls_ is needed, combine the above two approaches. + +### Custom Layout +Provided _color controls_ include hue/saturation palettes (circular or rectangular), sliders for saturation, brightness and for RGB components and a picked color preview control. + +### Custom Controls & Behavior +Additional can by added by implementing [`ColorControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ColorControl.swift) protocol. + + +#### Available Color Controls + +Each _color control_ has some properties (some of them can be set in storyboard) that can be used for customisation of that control's look and feel. +This is the list of included _color controls_: + +[`ColorPreviewWithHex`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ColorPreviewWithHex.swift) +[`RadialPaletteControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/PaletteControls.swift) +[`RectangularPaletteControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/PaletteControls.swift) +[`SaturationSliderControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift) +[`BrightnessSliderControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift) +[`RedSliderControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift) +[`GreenSliderControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift) +[`BlueSliderControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ComponentSliderControls.swift) + +If you want to customize your color picker, you can choose and lay out _color controls_ that you want, set their properties if needed and [connect them by adding them to the same _color picker controller_](#connecting-color-controls). + +![Working with Color Picker in XCode Storyboard](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Working_with_flex_color_picker_from_storyboard.png) + +#### Connecting Color Controls +In storyboard, lay out _color controls_ and set their classes in [_Identity Inspector_](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Identity_Inspector.jpg) to classes of controls you want to use. For example, set _class_ field in in [_Identity Inspector_](https://github.com/RastislavMirek/FlexColorPicker/blob/master/GifsAndScreenshots/Identity_Inspector.jpg) to text "RadialPaletteControl". Then set controller's class to `CustomColorPickerViewController`, open its _Connection Inspector_ (right side of [this image](#storyboardscreenshot)) and connect corresponding outlets the controls. The same can be done in code simply by assigning _color controls_ to appropriate properties of `CustomColorPickerViewController`. + +If you cannot subclass `CustomColorPickerViewController` e.g. because your controller is a subclass of another class use `ColorPickerController` instead. It can also be used in storyboard as interface builder custom object. It has same properties as `CustomColorPickerViewController` (actually, `CustomColorPickerViewController` is just a convenience wrapper for `ColorPickerController`). You can also add _color controls_ to it via `ColorPickerController.addControl(:)` so you are not limited to properties. + +Once added to a _color picker controller_ (e.g. `ColorPickerController`) a _color control_ will be synchronized with other controls managed by the same controller together selecting a single color. + +### Extending & Overriding +FlexColorPicker is made to be tweaked and extended with minimum effort. You can add you own _color control_ by implementing `ColorControl` protocol or extending one of following subclass-ready classes: + +- [`AbstractColorControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/AbstractColorControl.swift) - aways subclass if possible +- [`AdjustedHitBoxColorControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/AdjustedHitBoxColorControl.swift) - provides extended hit box margin around the control +- [`ColorSliderControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ColorSliderControl.swift) - e.g. if you need sliders for another color model then HSB or RGB +- [`ColorPaletteControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ColorPaletteControl.swift) - if you want to create another color palette + +In many cases there will be no need to subclass `ColorSliderControl` or `ColorPaletteControl`. They both relay on their _color delegates_ in how they handle color updates, present themselves and how they interpret user interactions. Therefore, you can instead implement `ColorSliderDelegate` or `ColorPaletteDelegate` protocols respectively to change look and behavior without changing the code of the control itself. + +Demo project has good examples on both approaches (overriding and composition) and their combination, feel free to check it. + +When subclassing `AbstractColorControl` or `AdjustedHitBoxColorControl` directly ( not via `ColorSliderControl` or `ColorPaletteControl`) you might want to override `gestureRecognizerShouldBegin(:)`. By default, no `UIPanGestureRecognizer` is allowed to recognize any gesture on instances of `AbstractColorControl`. Depending on type of your _custom color control_ you might want to allow `UIPanGestureRecognizer` to recognize the gesture in some (or all) cases. For example, horizontal slider will want to prevent `UIPanGestureRecognizer` from recognizing horizontal pan gesture because that means changing slider's value. In the same time, it may allow `UIPanGestureRecognizer` to recognize any vertical pan gesture as by those user probably ment to scoll the superview of the slider (it might be `UIScrollView`), not changing slider's value. + +## Tips & Troubleshooting +All classes and functions of FlexColorPicker have great in-code documentation. It is there to help you when you are unsure about that class or function's purposer or usage. +☛ Just option-click name of any FlexColorPicker class or function in XCode to display detailed documentation. + +When setting up slider controls in storyboard it is a good practise to set its background to be transparent. [Alignment rectangle](https://developer.apple.com/documentation/uikit/uiview/1622648-alignmentrectinsets) ([rectangle that autolayout uses to lay out the control](https://useyourloaf.com/blog/auto-layout-and-alignment-rectangles/)) is smaller than the actual frame of the slider to allow for extra hit box margin as well as background framing of the slider. Therefore, if background is solid white it can overlap other views close to it. +☛ If you do not want this behavior, set Hit Box Inset to 0 in Attributes Inspector or set `hitBoxInset` to `0` in code. + +`ColorPreviewWithHex` can be tapped. When it it tapped, `ColorPickerController` calls `ColorPickerDelegate.colorPicker(_:selectedColor:usingControl:)` on its delegate. +☛ You can communicate this feature to your users or opt out by setting `ColorPreviewWithHex.tapToConfirm` to `false`. + + #### Scrolling & Modal Presentation Concerns +When you create your own [_color controls_](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/ColorControl.swift) that do not inherit from [`AbstractColorControl`](https://github.com/RastislavMirek/FlexColorPicker/blob/master/FlexColorPicker/Classes/Controls/AbstractColorControl.swift) and add use them with a modally presented `UIViewController`, their pan gestures may conflict with dismiss modal gesture on iOS 13. The pan gesture may also conflict with scrolling when they are subclass of `UIScrollView`. +☛ Solve this by adding following code to the view that receives touches (bottom most one in view hierarchy) of your custom _color control_: + + override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + return !(gestureRecognizer is UIPanGestureRecognizer) + } + + +Implementation of all provided _color controls_ (including `AbstractColorControl` and `AdjustedHitBoxColorControl`) overrides `gestureRecognizerShouldBegin(:)` in order to ensure that the _color controls_ work correctly when embeded inside `UIScrollView`s and iOS 13 modal view conctollers presented modally. The implametation prevents instaces of `UIPanGestureRecognizer` from recognizing any gesture if some condition is met. In some rare cases this may interfere with custom `UIPanGestureRecognizer`s that you add to view hierarchy. +☛ Solve this by subclassing the _color control_ that you want to use with your `UIPanGestureRecognizer` and overriding `gestureRecognizerShouldBegin(:)` so that the gesture is recognized. + + +When you add a subview to a _color control_ (either your _custom color control_ or any of the provided ones), that subview has user interaction enabled and the _color control_ is embedded inside a `UIScrollView` or iOS 13 modally presented view controller you may experience following issue when panning/swiping that subview: Panning/swiping meant to interact with your _control control_ might be interpreted as scrolling/dismissing the controller or vice-versa. +☛ Solve this by adding following code to the subview that you added to the _color control_ and setting the delegate to the color control itself: + + weak var delegate: LimitedGestureViewDelegate? + + override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + guard let delegate = delegate else { + return !(gestureRecognizer is UIPanGestureRecognizer) + } + return delegate.gestureRecognizerShouldBegin(gestureRecognizer) + } + + +## Getting in Touch +If you like it, have a question or want to hire iOS developers shoot me a message at + +**[my first name, see profile] _at_ [epytysae spelled backwards] _dot_ [first 4 letters of word information]** + +Emails go directly to author of FlexColorPicker, cryptic format is just spam bot protection. + +Suggestions, feedback, bug reports & pull requests are very welcomed. + +## Thanks +Visual of slider control was inspired by popular Objective-C library HRColorPicker. Thank you for using FlexColorPicker! If you just have 3 seconds to give back, please star this repository. diff --git a/Pods/MBProgressHUD/LICENSE b/Pods/MBProgressHUD/LICENSE new file mode 100644 index 0000000..d7f0647 --- /dev/null +++ b/Pods/MBProgressHUD/LICENSE @@ -0,0 +1,19 @@ +Copyright © 2009-2020 Matej Bukovinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/Pods/MBProgressHUD/MBProgressHUD.h b/Pods/MBProgressHUD/MBProgressHUD.h new file mode 100644 index 0000000..38b5004 --- /dev/null +++ b/Pods/MBProgressHUD/MBProgressHUD.h @@ -0,0 +1,411 @@ +// +// MBProgressHUD.h +// Version 1.2.0 +// Created by Matej Bukovinski on 2.4.09. +// + +// This code is distributed under the terms and conditions of the MIT license. + +// Copyright © 2009-2016 Matej Bukovinski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import +#import + +@class MBBackgroundView; +@protocol MBProgressHUDDelegate; + + +extern CGFloat const MBProgressMaxOffset; + +typedef NS_ENUM(NSInteger, MBProgressHUDMode) { + /// UIActivityIndicatorView. + MBProgressHUDModeIndeterminate, + /// A round, pie-chart like, progress view. + MBProgressHUDModeDeterminate, + /// Horizontal progress bar. + MBProgressHUDModeDeterminateHorizontalBar, + /// Ring-shaped progress view. + MBProgressHUDModeAnnularDeterminate, + /// Shows a custom view. + MBProgressHUDModeCustomView, + /// Shows only labels. + MBProgressHUDModeText +}; + +typedef NS_ENUM(NSInteger, MBProgressHUDAnimation) { + /// Opacity animation + MBProgressHUDAnimationFade, + /// Opacity + scale animation (zoom in when appearing zoom out when disappearing) + MBProgressHUDAnimationZoom, + /// Opacity + scale animation (zoom out style) + MBProgressHUDAnimationZoomOut, + /// Opacity + scale animation (zoom in style) + MBProgressHUDAnimationZoomIn +}; + +typedef NS_ENUM(NSInteger, MBProgressHUDBackgroundStyle) { + /// Solid color background + MBProgressHUDBackgroundStyleSolidColor, + /// UIVisualEffectView or UIToolbar.layer background view + MBProgressHUDBackgroundStyleBlur +}; + +typedef void (^MBProgressHUDCompletionBlock)(void); + + +NS_ASSUME_NONNULL_BEGIN + + +/** + * Displays a simple HUD window containing a progress indicator and two optional labels for short messages. + * + * This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class. + * The MBProgressHUD window spans over the entire space given to it by the initWithFrame: constructor and catches all + * user input on this region, thereby preventing the user operations on components below the view. + * + * @note To still allow touches to pass through the HUD, you can set hud.userInteractionEnabled = NO. + * @attention MBProgressHUD is a UI class and should therefore only be accessed on the main thread. + */ +@interface MBProgressHUD : UIView + +/** + * Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:. + * + * @note This method sets removeFromSuperViewOnHide. The HUD will automatically be removed from the view hierarchy when hidden. + * + * @param view The view that the HUD will be added to + * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use + * animations while appearing. + * @return A reference to the created HUD. + * + * @see hideHUDForView:animated: + * @see animationType + */ ++ (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated; + +/// @name Showing and hiding + +/** + * Finds the top-most HUD subview that hasn't finished and hides it. The counterpart to this method is showHUDAddedTo:animated:. + * + * @note This method sets removeFromSuperViewOnHide. The HUD will automatically be removed from the view hierarchy when hidden. + * + * @param view The view that is going to be searched for a HUD subview. + * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use + * animations while disappearing. + * @return YES if a HUD was found and removed, NO otherwise. + * + * @see showHUDAddedTo:animated: + * @see animationType + */ ++ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated; + +/** + * Finds the top-most HUD subview that hasn't finished and returns it. + * + * @param view The view that is going to be searched. + * @return A reference to the last HUD subview discovered. + */ ++ (nullable MBProgressHUD *)HUDForView:(UIView *)view NS_SWIFT_NAME(forView(_:)); + +/** + * A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with + * view.bounds as the parameter. + * + * @param view The view instance that will provide the bounds for the HUD. Should be the same instance as + * the HUD's superview (i.e., the view that the HUD will be added to). + */ +- (instancetype)initWithView:(UIView *)view; + +/** + * Displays the HUD. + * + * @note You need to make sure that the main thread completes its run loop soon after this method call so that + * the user interface can be updated. Call this method when your task is already set up to be executed in a new thread + * (e.g., when using something like NSOperation or making an asynchronous call like NSURLRequest). + * + * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use + * animations while appearing. + * + * @see animationType + */ +- (void)showAnimated:(BOOL)animated; + +/** + * Hides the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to + * hide the HUD when your task completes. + * + * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use + * animations while disappearing. + * + * @see animationType + */ +- (void)hideAnimated:(BOOL)animated; + +/** + * Hides the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to + * hide the HUD when your task completes. + * + * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use + * animations while disappearing. + * @param delay Delay in seconds until the HUD is hidden. + * + * @see animationType + */ +- (void)hideAnimated:(BOOL)animated afterDelay:(NSTimeInterval)delay; + +/** + * The HUD delegate object. Receives HUD state notifications. + */ +@property (weak, nonatomic) id delegate; + +/** + * Called after the HUD is hidden. + */ +@property (copy, nullable) MBProgressHUDCompletionBlock completionBlock; + +/** + * Grace period is the time (in seconds) that the invoked method may be run without + * showing the HUD. If the task finishes before the grace time runs out, the HUD will + * not be shown at all. + * This may be used to prevent HUD display for very short tasks. + * Defaults to 0 (no grace time). + * @note The graceTime needs to be set before the hud is shown. You thus can't use `showHUDAddedTo:animated:`, + * but instead need to alloc / init the HUD, configure the grace time and than show it manually. + */ +@property (assign, nonatomic) NSTimeInterval graceTime; + +/** + * The minimum time (in seconds) that the HUD is shown. + * This avoids the problem of the HUD being shown and than instantly hidden. + * Defaults to 0 (no minimum show time). + */ +@property (assign, nonatomic) NSTimeInterval minShowTime; + +/** + * Removes the HUD from its parent view when hidden. + * Defaults to NO. + */ +@property (assign, nonatomic) BOOL removeFromSuperViewOnHide; + +/// @name Appearance + +/** + * MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate. + */ +@property (assign, nonatomic) MBProgressHUDMode mode; + +/** + * A color that gets forwarded to all labels and supported indicators. Also sets the tintColor + * for custom views on iOS 7+. Set to nil to manage color individually. + * Defaults to semi-translucent black on iOS 7 and later and white on earlier iOS versions. + */ +@property (strong, nonatomic, nullable) UIColor *contentColor UI_APPEARANCE_SELECTOR; + +/** + * The animation type that should be used when the HUD is shown and hidden. + */ +@property (assign, nonatomic) MBProgressHUDAnimation animationType UI_APPEARANCE_SELECTOR; + +/** + * The bezel offset relative to the center of the view. You can use MBProgressMaxOffset + * and -MBProgressMaxOffset to move the HUD all the way to the screen edge in each direction. + * E.g., CGPointMake(0.f, MBProgressMaxOffset) would position the HUD centered on the bottom edge. + */ +@property (assign, nonatomic) CGPoint offset UI_APPEARANCE_SELECTOR; + +/** + * The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views). + * This also represents the minimum bezel distance to the edge of the HUD view. + * Defaults to 20.f + */ +@property (assign, nonatomic) CGFloat margin UI_APPEARANCE_SELECTOR; + +/** + * The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size). + */ +@property (assign, nonatomic) CGSize minSize UI_APPEARANCE_SELECTOR; + +/** + * Force the HUD dimensions to be equal if possible. + */ +@property (assign, nonatomic, getter = isSquare) BOOL square UI_APPEARANCE_SELECTOR; + +/** + * When enabled, the bezel center gets slightly affected by the device accelerometer data. + * Defaults to NO. + * + * @note This can cause main thread checker assertions on certain devices. https://github.com/jdg/MBProgressHUD/issues/552 + */ +@property (assign, nonatomic, getter=areDefaultMotionEffectsEnabled) BOOL defaultMotionEffectsEnabled UI_APPEARANCE_SELECTOR; + +/// @name Progress + +/** + * The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0. + */ +@property (assign, nonatomic) float progress; + +/// @name ProgressObject + +/** + * The NSProgress object feeding the progress information to the progress indicator. + */ +@property (strong, nonatomic, nullable) NSProgress *progressObject; + +/// @name Views + +/** + * The view containing the labels and indicator (or customView). + */ +@property (strong, nonatomic, readonly) MBBackgroundView *bezelView; + +/** + * View covering the entire HUD area, placed behind bezelView. + */ +@property (strong, nonatomic, readonly) MBBackgroundView *backgroundView; + +/** + * The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView. + * The view should implement intrinsicContentSize for proper sizing. For best results use approximately 37 by 37 pixels. + */ +@property (strong, nonatomic, nullable) UIView *customView; + +/** + * A label that holds an optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit + * the entire text. + */ +@property (strong, nonatomic, readonly) UILabel *label; + +/** + * A label that holds an optional details message displayed below the labelText message. The details text can span multiple lines. + */ +@property (strong, nonatomic, readonly) UILabel *detailsLabel; + +/** + * A button that is placed below the labels. Visible only if a target / action is added and a title is assigned.. + */ +@property (strong, nonatomic, readonly) UIButton *button; + +@end + + +@protocol MBProgressHUDDelegate + +@optional + +/** + * Called after the HUD was fully hidden from the screen. + */ +- (void)hudWasHidden:(MBProgressHUD *)hud; + +@end + + +/** + * A progress view for showing definite progress by filling up a circle (pie chart). + */ +@interface MBRoundProgressView : UIView + +/** + * Progress (0.0 to 1.0) + */ +@property (nonatomic, assign) float progress; + +/** + * Indicator progress color. + * Defaults to white [UIColor whiteColor]. + */ +@property (nonatomic, strong) UIColor *progressTintColor; + +/** + * Indicator background (non-progress) color. + * Only applicable on iOS versions older than iOS 7. + * Defaults to translucent white (alpha 0.1). + */ +@property (nonatomic, strong) UIColor *backgroundTintColor; + +/* + * Display mode - NO = round or YES = annular. Defaults to round. + */ +@property (nonatomic, assign, getter = isAnnular) BOOL annular; + +@end + + +/** + * A flat bar progress view. + */ +@interface MBBarProgressView : UIView + +/** + * Progress (0.0 to 1.0) + */ +@property (nonatomic, assign) float progress; + +/** + * Bar border line color. + * Defaults to white [UIColor whiteColor]. + */ +@property (nonatomic, strong) UIColor *lineColor; + +/** + * Bar background color. + * Defaults to clear [UIColor clearColor]; + */ +@property (nonatomic, strong) UIColor *progressRemainingColor; + +/** + * Bar progress color. + * Defaults to white [UIColor whiteColor]. + */ +@property (nonatomic, strong) UIColor *progressColor; + +@end + + +@interface MBBackgroundView : UIView + +/** + * The background style. + * Defaults to MBProgressHUDBackgroundStyleBlur. + */ +@property (nonatomic) MBProgressHUDBackgroundStyle style; + +/** + * The blur effect style, when using MBProgressHUDBackgroundStyleBlur. + * Defaults to UIBlurEffectStyleLight. + */ +@property (nonatomic) UIBlurEffectStyle blurEffectStyle; + +/** + * The background color or the blur tint color. + * + * Defaults to nil on iOS 13 and later and + * `[UIColor colorWithWhite:0.8f alpha:0.6f]` + * on older systems. + */ +@property (nonatomic, strong, nullable) UIColor *color; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/MBProgressHUD/MBProgressHUD.m b/Pods/MBProgressHUD/MBProgressHUD.m new file mode 100644 index 0000000..a2829a3 --- /dev/null +++ b/Pods/MBProgressHUD/MBProgressHUD.m @@ -0,0 +1,1194 @@ +// +// MBProgressHUD.m +// Version 1.2.0 +// Created by Matej Bukovinski on 2.4.09. +// + +#import "MBProgressHUD.h" +#import + +#define MBMainThreadAssert() NSAssert([NSThread isMainThread], @"MBProgressHUD needs to be accessed on the main thread."); + +CGFloat const MBProgressMaxOffset = 1000000.f; + +static const CGFloat MBDefaultPadding = 4.f; +static const CGFloat MBDefaultLabelFontSize = 16.f; +static const CGFloat MBDefaultDetailsLabelFontSize = 12.f; + + +@interface MBProgressHUD () + +@property (nonatomic, assign) BOOL useAnimation; +@property (nonatomic, assign, getter=hasFinished) BOOL finished; +@property (nonatomic, strong) UIView *indicator; +@property (nonatomic, strong) NSDate *showStarted; +@property (nonatomic, strong) NSArray *paddingConstraints; +@property (nonatomic, strong) NSArray *bezelConstraints; +@property (nonatomic, strong) UIView *topSpacer; +@property (nonatomic, strong) UIView *bottomSpacer; +@property (nonatomic, strong) UIMotionEffectGroup *bezelMotionEffects; +@property (nonatomic, weak) NSTimer *graceTimer; +@property (nonatomic, weak) NSTimer *minShowTimer; +@property (nonatomic, weak) NSTimer *hideDelayTimer; +@property (nonatomic, weak) CADisplayLink *progressObjectDisplayLink; + +@end + + +@interface MBProgressHUDRoundedButton : UIButton +@end + + +@implementation MBProgressHUD + +#pragma mark - Class methods + ++ (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated { + MBProgressHUD *hud = [[self alloc] initWithView:view]; + hud.removeFromSuperViewOnHide = YES; + [view addSubview:hud]; + [hud showAnimated:animated]; + return hud; +} + ++ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated { + MBProgressHUD *hud = [self HUDForView:view]; + if (hud != nil) { + hud.removeFromSuperViewOnHide = YES; + [hud hideAnimated:animated]; + return YES; + } + return NO; +} + ++ (MBProgressHUD *)HUDForView:(UIView *)view { + NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator]; + for (UIView *subview in subviewsEnum) { + if ([subview isKindOfClass:self]) { + MBProgressHUD *hud = (MBProgressHUD *)subview; + if (hud.hasFinished == NO) { + return hud; + } + } + } + return nil; +} + +#pragma mark - Lifecycle + +- (void)commonInit { + // Set default values for properties + _animationType = MBProgressHUDAnimationFade; + _mode = MBProgressHUDModeIndeterminate; + _margin = 20.0f; + _defaultMotionEffectsEnabled = NO; + + if (@available(iOS 13.0, tvOS 13, *)) { + _contentColor = [[UIColor labelColor] colorWithAlphaComponent:0.7f]; + } else { + _contentColor = [UIColor colorWithWhite:0.f alpha:0.7f]; + } + + // Transparent background + self.opaque = NO; + self.backgroundColor = [UIColor clearColor]; + // Make it invisible for now + self.alpha = 0.0f; + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.layer.allowsGroupOpacity = NO; + + [self setupViews]; + [self updateIndicators]; + [self registerForNotifications]; +} + +- (instancetype)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + [self commonInit]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + if ((self = [super initWithCoder:aDecoder])) { + [self commonInit]; + } + return self; +} + +- (id)initWithView:(UIView *)view { + NSAssert(view, @"View must not be nil."); + return [self initWithFrame:view.bounds]; +} + +- (void)dealloc { + [self unregisterFromNotifications]; +} + +#pragma mark - Show & hide + +- (void)showAnimated:(BOOL)animated { + MBMainThreadAssert(); + [self.minShowTimer invalidate]; + self.useAnimation = animated; + self.finished = NO; + // If the grace time is set, postpone the HUD display + if (self.graceTime > 0.0) { + NSTimer *timer = [NSTimer timerWithTimeInterval:self.graceTime target:self selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO]; + [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; + self.graceTimer = timer; + } + // ... otherwise show the HUD immediately + else { + [self showUsingAnimation:self.useAnimation]; + } +} + +- (void)hideAnimated:(BOOL)animated { + MBMainThreadAssert(); + [self.graceTimer invalidate]; + self.useAnimation = animated; + self.finished = YES; + // If the minShow time is set, calculate how long the HUD was shown, + // and postpone the hiding operation if necessary + if (self.minShowTime > 0.0 && self.showStarted) { + NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:self.showStarted]; + if (interv < self.minShowTime) { + NSTimer *timer = [NSTimer timerWithTimeInterval:(self.minShowTime - interv) target:self selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO]; + [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; + self.minShowTimer = timer; + return; + } + } + // ... otherwise hide the HUD immediately + [self hideUsingAnimation:self.useAnimation]; +} + +- (void)hideAnimated:(BOOL)animated afterDelay:(NSTimeInterval)delay { + // Cancel any scheduled hideAnimated:afterDelay: calls + [self.hideDelayTimer invalidate]; + + NSTimer *timer = [NSTimer timerWithTimeInterval:delay target:self selector:@selector(handleHideTimer:) userInfo:@(animated) repeats:NO]; + [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; + self.hideDelayTimer = timer; +} + +#pragma mark - Timer callbacks + +- (void)handleGraceTimer:(NSTimer *)theTimer { + // Show the HUD only if the task is still running + if (!self.hasFinished) { + [self showUsingAnimation:self.useAnimation]; + } +} + +- (void)handleMinShowTimer:(NSTimer *)theTimer { + [self hideUsingAnimation:self.useAnimation]; +} + +- (void)handleHideTimer:(NSTimer *)timer { + [self hideAnimated:[timer.userInfo boolValue]]; +} + +#pragma mark - View Hierrarchy + +- (void)didMoveToSuperview { + [self updateForCurrentOrientationAnimated:NO]; +} + +#pragma mark - Internal show & hide operations + +- (void)showUsingAnimation:(BOOL)animated { + // Cancel any previous animations + [self.bezelView.layer removeAllAnimations]; + [self.backgroundView.layer removeAllAnimations]; + + // Cancel any scheduled hideAnimated:afterDelay: calls + [self.hideDelayTimer invalidate]; + + self.showStarted = [NSDate date]; + self.alpha = 1.f; + + // Needed in case we hide and re-show with the same NSProgress object attached. + [self setNSProgressDisplayLinkEnabled:YES]; + + // Set up motion effects only at this point to avoid needlessly + // creating the effect if it was disabled after initialization. + [self updateBezelMotionEffects]; + + if (animated) { + [self animateIn:YES withType:self.animationType completion:NULL]; + } else { + self.bezelView.alpha = 1.f; + self.backgroundView.alpha = 1.f; + } +} + +- (void)hideUsingAnimation:(BOOL)animated { + // Cancel any scheduled hideAnimated:afterDelay: calls. + // This needs to happen here instead of in done, + // to avoid races if another hideAnimated:afterDelay: + // call comes in while the HUD is animating out. + [self.hideDelayTimer invalidate]; + + if (animated && self.showStarted) { + self.showStarted = nil; + [self animateIn:NO withType:self.animationType completion:^(BOOL finished) { + [self done]; + }]; + } else { + self.showStarted = nil; + self.bezelView.alpha = 0.f; + self.backgroundView.alpha = 1.f; + [self done]; + } +} + +- (void)animateIn:(BOOL)animatingIn withType:(MBProgressHUDAnimation)type completion:(void(^)(BOOL finished))completion { + // Automatically determine the correct zoom animation type + if (type == MBProgressHUDAnimationZoom) { + type = animatingIn ? MBProgressHUDAnimationZoomIn : MBProgressHUDAnimationZoomOut; + } + + CGAffineTransform small = CGAffineTransformMakeScale(0.5f, 0.5f); + CGAffineTransform large = CGAffineTransformMakeScale(1.5f, 1.5f); + + // Set starting state + UIView *bezelView = self.bezelView; + if (animatingIn && bezelView.alpha == 0.f && type == MBProgressHUDAnimationZoomIn) { + bezelView.transform = small; + } else if (animatingIn && bezelView.alpha == 0.f && type == MBProgressHUDAnimationZoomOut) { + bezelView.transform = large; + } + + // Perform animations + dispatch_block_t animations = ^{ + if (animatingIn) { + bezelView.transform = CGAffineTransformIdentity; + } else if (!animatingIn && type == MBProgressHUDAnimationZoomIn) { + bezelView.transform = large; + } else if (!animatingIn && type == MBProgressHUDAnimationZoomOut) { + bezelView.transform = small; + } + CGFloat alpha = animatingIn ? 1.f : 0.f; + bezelView.alpha = alpha; + self.backgroundView.alpha = alpha; + }; + [UIView animateWithDuration:0.3 delay:0. usingSpringWithDamping:1.f initialSpringVelocity:0.f options:UIViewAnimationOptionBeginFromCurrentState animations:animations completion:completion]; +} + +- (void)done { + [self setNSProgressDisplayLinkEnabled:NO]; + + if (self.hasFinished) { + self.alpha = 0.0f; + if (self.removeFromSuperViewOnHide) { + [self removeFromSuperview]; + } + } + MBProgressHUDCompletionBlock completionBlock = self.completionBlock; + if (completionBlock) { + completionBlock(); + } + id delegate = self.delegate; + if ([delegate respondsToSelector:@selector(hudWasHidden:)]) { + [delegate performSelector:@selector(hudWasHidden:) withObject:self]; + } +} + +#pragma mark - UI + +- (void)setupViews { + UIColor *defaultColor = self.contentColor; + + MBBackgroundView *backgroundView = [[MBBackgroundView alloc] initWithFrame:self.bounds]; + backgroundView.style = MBProgressHUDBackgroundStyleSolidColor; + backgroundView.backgroundColor = [UIColor clearColor]; + backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + backgroundView.alpha = 0.f; + [self addSubview:backgroundView]; + _backgroundView = backgroundView; + + MBBackgroundView *bezelView = [MBBackgroundView new]; + bezelView.translatesAutoresizingMaskIntoConstraints = NO; + bezelView.layer.cornerRadius = 5.f; + bezelView.alpha = 0.f; + [self addSubview:bezelView]; + _bezelView = bezelView; + + UILabel *label = [UILabel new]; + label.adjustsFontSizeToFitWidth = NO; + label.textAlignment = NSTextAlignmentCenter; + label.textColor = defaultColor; + label.font = [UIFont boldSystemFontOfSize:MBDefaultLabelFontSize]; + label.opaque = NO; + label.backgroundColor = [UIColor clearColor]; + _label = label; + + UILabel *detailsLabel = [UILabel new]; + detailsLabel.adjustsFontSizeToFitWidth = NO; + detailsLabel.textAlignment = NSTextAlignmentCenter; + detailsLabel.textColor = defaultColor; + detailsLabel.numberOfLines = 0; + detailsLabel.font = [UIFont boldSystemFontOfSize:MBDefaultDetailsLabelFontSize]; + detailsLabel.opaque = NO; + detailsLabel.backgroundColor = [UIColor clearColor]; + _detailsLabel = detailsLabel; + + UIButton *button = [MBProgressHUDRoundedButton buttonWithType:UIButtonTypeCustom]; + button.titleLabel.textAlignment = NSTextAlignmentCenter; + button.titleLabel.font = [UIFont boldSystemFontOfSize:MBDefaultDetailsLabelFontSize]; + [button setTitleColor:defaultColor forState:UIControlStateNormal]; + _button = button; + + for (UIView *view in @[label, detailsLabel, button]) { + view.translatesAutoresizingMaskIntoConstraints = NO; + [view setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisHorizontal]; + [view setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisVertical]; + [bezelView addSubview:view]; + } + + UIView *topSpacer = [UIView new]; + topSpacer.translatesAutoresizingMaskIntoConstraints = NO; + topSpacer.hidden = YES; + [bezelView addSubview:topSpacer]; + _topSpacer = topSpacer; + + UIView *bottomSpacer = [UIView new]; + bottomSpacer.translatesAutoresizingMaskIntoConstraints = NO; + bottomSpacer.hidden = YES; + [bezelView addSubview:bottomSpacer]; + _bottomSpacer = bottomSpacer; +} + +- (void)updateIndicators { + UIView *indicator = self.indicator; + BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]]; + BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]]; + + MBProgressHUDMode mode = self.mode; + if (mode == MBProgressHUDModeIndeterminate) { + if (!isActivityIndicator) { + // Update to indeterminate indicator + UIActivityIndicatorView *activityIndicator; + [indicator removeFromSuperview]; +#if !TARGET_OS_MACCATALYST + if (@available(iOS 13.0, tvOS 13.0, *)) { +#endif + activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleLarge]; + activityIndicator.color = [UIColor whiteColor]; +#if !TARGET_OS_MACCATALYST + } else { + activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + } +#endif + [activityIndicator startAnimating]; + indicator = activityIndicator; + [self.bezelView addSubview:indicator]; + } + } + else if (mode == MBProgressHUDModeDeterminateHorizontalBar) { + // Update to bar determinate indicator + [indicator removeFromSuperview]; + indicator = [[MBBarProgressView alloc] init]; + [self.bezelView addSubview:indicator]; + } + else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) { + if (!isRoundIndicator) { + // Update to determinante indicator + [indicator removeFromSuperview]; + indicator = [[MBRoundProgressView alloc] init]; + [self.bezelView addSubview:indicator]; + } + if (mode == MBProgressHUDModeAnnularDeterminate) { + [(MBRoundProgressView *)indicator setAnnular:YES]; + } + } + else if (mode == MBProgressHUDModeCustomView && self.customView != indicator) { + // Update custom view indicator + [indicator removeFromSuperview]; + indicator = self.customView; + [self.bezelView addSubview:indicator]; + } + else if (mode == MBProgressHUDModeText) { + [indicator removeFromSuperview]; + indicator = nil; + } + indicator.translatesAutoresizingMaskIntoConstraints = NO; + self.indicator = indicator; + + if ([indicator respondsToSelector:@selector(setProgress:)]) { + [(id)indicator setValue:@(self.progress) forKey:@"progress"]; + } + + [indicator setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisHorizontal]; + [indicator setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisVertical]; + + [self updateViewsForColor:self.contentColor]; + [self setNeedsUpdateConstraints]; +} + +- (void)updateViewsForColor:(UIColor *)color { + if (!color) return; + + self.label.textColor = color; + self.detailsLabel.textColor = color; + [self.button setTitleColor:color forState:UIControlStateNormal]; + + // UIAppearance settings are prioritized. If they are preset the set color is ignored. + + UIView *indicator = self.indicator; + if ([indicator isKindOfClass:[UIActivityIndicatorView class]]) { + UIActivityIndicatorView *appearance = nil; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000 + appearance = [UIActivityIndicatorView appearanceWhenContainedIn:[MBProgressHUD class], nil]; +#else + // For iOS 9+ + appearance = [UIActivityIndicatorView appearanceWhenContainedInInstancesOfClasses:@[[MBProgressHUD class]]]; +#endif + + if (appearance.color == nil) { + ((UIActivityIndicatorView *)indicator).color = color; + } + } else if ([indicator isKindOfClass:[MBRoundProgressView class]]) { + MBRoundProgressView *appearance = nil; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000 + appearance = [MBRoundProgressView appearanceWhenContainedIn:[MBProgressHUD class], nil]; +#else + appearance = [MBRoundProgressView appearanceWhenContainedInInstancesOfClasses:@[[MBProgressHUD class]]]; +#endif + if (appearance.progressTintColor == nil) { + ((MBRoundProgressView *)indicator).progressTintColor = color; + } + if (appearance.backgroundTintColor == nil) { + ((MBRoundProgressView *)indicator).backgroundTintColor = [color colorWithAlphaComponent:0.1]; + } + } else if ([indicator isKindOfClass:[MBBarProgressView class]]) { + MBBarProgressView *appearance = nil; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000 + appearance = [MBBarProgressView appearanceWhenContainedIn:[MBProgressHUD class], nil]; +#else + appearance = [MBBarProgressView appearanceWhenContainedInInstancesOfClasses:@[[MBProgressHUD class]]]; +#endif + if (appearance.progressColor == nil) { + ((MBBarProgressView *)indicator).progressColor = color; + } + if (appearance.lineColor == nil) { + ((MBBarProgressView *)indicator).lineColor = color; + } + } else { + [indicator setTintColor:color]; + } +} + +- (void)updateBezelMotionEffects { + MBBackgroundView *bezelView = self.bezelView; + UIMotionEffectGroup *bezelMotionEffects = self.bezelMotionEffects; + + if (self.defaultMotionEffectsEnabled && !bezelMotionEffects) { + CGFloat effectOffset = 10.f; + UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis]; + effectX.maximumRelativeValue = @(effectOffset); + effectX.minimumRelativeValue = @(-effectOffset); + + UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis]; + effectY.maximumRelativeValue = @(effectOffset); + effectY.minimumRelativeValue = @(-effectOffset); + + UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init]; + group.motionEffects = @[effectX, effectY]; + + self.bezelMotionEffects = group; + [bezelView addMotionEffect:group]; + } else if (bezelMotionEffects) { + self.bezelMotionEffects = nil; + [bezelView removeMotionEffect:bezelMotionEffects]; + } +} + +#pragma mark - Layout + +- (void)updateConstraints { + UIView *bezel = self.bezelView; + UIView *topSpacer = self.topSpacer; + UIView *bottomSpacer = self.bottomSpacer; + CGFloat margin = self.margin; + NSMutableArray *bezelConstraints = [NSMutableArray array]; + NSDictionary *metrics = @{@"margin": @(margin)}; + + NSMutableArray *subviews = [NSMutableArray arrayWithObjects:self.topSpacer, self.label, self.detailsLabel, self.button, self.bottomSpacer, nil]; + if (self.indicator) [subviews insertObject:self.indicator atIndex:1]; + + // Remove existing constraints + [self removeConstraints:self.constraints]; + [topSpacer removeConstraints:topSpacer.constraints]; + [bottomSpacer removeConstraints:bottomSpacer.constraints]; + if (self.bezelConstraints) { + [bezel removeConstraints:self.bezelConstraints]; + self.bezelConstraints = nil; + } + + // Center bezel in container (self), applying the offset if set + CGPoint offset = self.offset; + NSMutableArray *centeringConstraints = [NSMutableArray array]; + [centeringConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.f constant:offset.x]]; + [centeringConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.f constant:offset.y]]; + [self applyPriority:998.f toConstraints:centeringConstraints]; + [self addConstraints:centeringConstraints]; + + // Ensure minimum side margin is kept + NSMutableArray *sideConstraints = [NSMutableArray array]; + [sideConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=margin)-[bezel]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(bezel)]]; + [sideConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=margin)-[bezel]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(bezel)]]; + [self applyPriority:999.f toConstraints:sideConstraints]; + [self addConstraints:sideConstraints]; + + // Minimum bezel size, if set + CGSize minimumSize = self.minSize; + if (!CGSizeEqualToSize(minimumSize, CGSizeZero)) { + NSMutableArray *minSizeConstraints = [NSMutableArray array]; + [minSizeConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:minimumSize.width]]; + [minSizeConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:minimumSize.height]]; + [self applyPriority:997.f toConstraints:minSizeConstraints]; + [bezelConstraints addObjectsFromArray:minSizeConstraints]; + } + + // Square aspect ratio, if set + if (self.square) { + NSLayoutConstraint *square = [NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeWidth multiplier:1.f constant:0]; + square.priority = 997.f; + [bezelConstraints addObject:square]; + } + + // Top and bottom spacing + [topSpacer addConstraint:[NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:margin]]; + [bottomSpacer addConstraint:[NSLayoutConstraint constraintWithItem:bottomSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:margin]]; + // Top and bottom spaces should be equal + [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bottomSpacer attribute:NSLayoutAttributeHeight multiplier:1.f constant:0.f]]; + + // Layout subviews in bezel + NSMutableArray *paddingConstraints = [NSMutableArray new]; + [subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { + // Center in bezel + [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f]]; + // Ensure the minimum edge margin is kept + [bezelConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=margin)-[view]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(view)]]; + // Element spacing + if (idx == 0) { + // First, ensure spacing to bezel edge + [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeTop multiplier:1.f constant:0.f]]; + } else if (idx == subviews.count - 1) { + // Last, ensure spacing to bezel edge + [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]]; + } + if (idx > 0) { + // Has previous + NSLayoutConstraint *padding = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:subviews[idx - 1] attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]; + [bezelConstraints addObject:padding]; + [paddingConstraints addObject:padding]; + } + }]; + + [bezel addConstraints:bezelConstraints]; + self.bezelConstraints = bezelConstraints; + + self.paddingConstraints = [paddingConstraints copy]; + [self updatePaddingConstraints]; + + [super updateConstraints]; +} + +- (void)layoutSubviews { + // There is no need to update constraints if they are going to + // be recreated in [super layoutSubviews] due to needsUpdateConstraints being set. + // This also avoids an issue on iOS 8, where updatePaddingConstraints + // would trigger a zombie object access. + if (!self.needsUpdateConstraints) { + [self updatePaddingConstraints]; + } + [super layoutSubviews]; +} + +- (void)updatePaddingConstraints { + // Set padding dynamically, depending on whether the view is visible or not + __block BOOL hasVisibleAncestors = NO; + [self.paddingConstraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *padding, NSUInteger idx, BOOL *stop) { + UIView *firstView = (UIView *)padding.firstItem; + UIView *secondView = (UIView *)padding.secondItem; + BOOL firstVisible = !firstView.hidden && !CGSizeEqualToSize(firstView.intrinsicContentSize, CGSizeZero); + BOOL secondVisible = !secondView.hidden && !CGSizeEqualToSize(secondView.intrinsicContentSize, CGSizeZero); + // Set if both views are visible or if there's a visible view on top that doesn't have padding + // added relative to the current view yet + padding.constant = (firstVisible && (secondVisible || hasVisibleAncestors)) ? MBDefaultPadding : 0.f; + hasVisibleAncestors |= secondVisible; + }]; +} + +- (void)applyPriority:(UILayoutPriority)priority toConstraints:(NSArray *)constraints { + for (NSLayoutConstraint *constraint in constraints) { + constraint.priority = priority; + } +} + +#pragma mark - Properties + +- (void)setMode:(MBProgressHUDMode)mode { + if (mode != _mode) { + _mode = mode; + [self updateIndicators]; + } +} + +- (void)setCustomView:(UIView *)customView { + if (customView != _customView) { + _customView = customView; + if (self.mode == MBProgressHUDModeCustomView) { + [self updateIndicators]; + } + } +} + +- (void)setOffset:(CGPoint)offset { + if (!CGPointEqualToPoint(offset, _offset)) { + _offset = offset; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setMargin:(CGFloat)margin { + if (margin != _margin) { + _margin = margin; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setMinSize:(CGSize)minSize { + if (!CGSizeEqualToSize(minSize, _minSize)) { + _minSize = minSize; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setSquare:(BOOL)square { + if (square != _square) { + _square = square; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setProgressObjectDisplayLink:(CADisplayLink *)progressObjectDisplayLink { + if (progressObjectDisplayLink != _progressObjectDisplayLink) { + [_progressObjectDisplayLink invalidate]; + + _progressObjectDisplayLink = progressObjectDisplayLink; + + [_progressObjectDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; + } +} + +- (void)setProgressObject:(NSProgress *)progressObject { + if (progressObject != _progressObject) { + _progressObject = progressObject; + [self setNSProgressDisplayLinkEnabled:YES]; + } +} + +- (void)setProgress:(float)progress { + if (progress != _progress) { + _progress = progress; + UIView *indicator = self.indicator; + if ([indicator respondsToSelector:@selector(setProgress:)]) { + [(id)indicator setValue:@(self.progress) forKey:@"progress"]; + } + } +} + +- (void)setContentColor:(UIColor *)contentColor { + if (contentColor != _contentColor && ![contentColor isEqual:_contentColor]) { + _contentColor = contentColor; + [self updateViewsForColor:contentColor]; + } +} + +- (void)setDefaultMotionEffectsEnabled:(BOOL)defaultMotionEffectsEnabled { + if (defaultMotionEffectsEnabled != _defaultMotionEffectsEnabled) { + _defaultMotionEffectsEnabled = defaultMotionEffectsEnabled; + [self updateBezelMotionEffects]; + } +} + +#pragma mark - NSProgress + +- (void)setNSProgressDisplayLinkEnabled:(BOOL)enabled { + // We're using CADisplayLink, because NSProgress can change very quickly and observing it may starve the main thread, + // so we're refreshing the progress only every frame draw + if (enabled && self.progressObject) { + // Only create if not already active. + if (!self.progressObjectDisplayLink) { + self.progressObjectDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateProgressFromProgressObject)]; + } + } else { + self.progressObjectDisplayLink = nil; + } +} + +- (void)updateProgressFromProgressObject { + self.progress = self.progressObject.fractionCompleted; +} + +#pragma mark - Notifications + +- (void)registerForNotifications { +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + [nc addObserver:self selector:@selector(statusBarOrientationDidChange:) + name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; +#endif +} + +- (void)unregisterFromNotifications { +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; +#endif +} + +#if !TARGET_OS_TV && !TARGET_OS_MACCATALYST +- (void)statusBarOrientationDidChange:(NSNotification *)notification { + UIView *superview = self.superview; + if (!superview) { + return; + } else { + [self updateForCurrentOrientationAnimated:YES]; + } +} +#endif + +- (void)updateForCurrentOrientationAnimated:(BOOL)animated { + // Stay in sync with the superview in any case + if (self.superview) { + self.frame = self.superview.bounds; + } + + // Not needed on iOS 8+, compile out when the deployment target allows, + // to avoid sharedApplication problems on extension targets +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 + // Only needed pre iOS 8 when added to a window + BOOL iOS8OrLater = kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0; + if (iOS8OrLater || ![self.superview isKindOfClass:[UIWindow class]]) return; + + // Make extension friendly. Will not get called on extensions (iOS 8+) due to the above check. + // This just ensures we don't get a warning about extension-unsafe API. + Class UIApplicationClass = NSClassFromString(@"UIApplication"); + if (!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) return; + + UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)]; + UIInterfaceOrientation orientation = application.statusBarOrientation; + CGFloat radians = 0; + + if (UIInterfaceOrientationIsLandscape(orientation)) { + radians = orientation == UIInterfaceOrientationLandscapeLeft ? -(CGFloat)M_PI_2 : (CGFloat)M_PI_2; + // Window coordinates differ! + self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width); + } else { + radians = orientation == UIInterfaceOrientationPortraitUpsideDown ? (CGFloat)M_PI : 0.f; + } + + if (animated) { + [UIView animateWithDuration:0.3 animations:^{ + self.transform = CGAffineTransformMakeRotation(radians); + }]; + } else { + self.transform = CGAffineTransformMakeRotation(radians); + } +#endif +} + +@end + + +@implementation MBRoundProgressView + +#pragma mark - Lifecycle + +- (id)init { + return [self initWithFrame:CGRectMake(0.f, 0.f, 37.f, 37.f)]; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + self.opaque = NO; + _progress = 0.f; + _annular = NO; + _progressTintColor = [[UIColor alloc] initWithWhite:1.f alpha:1.f]; + _backgroundTintColor = [[UIColor alloc] initWithWhite:1.f alpha:.1f]; + } + return self; +} + +#pragma mark - Layout + +- (CGSize)intrinsicContentSize { + return CGSizeMake(37.f, 37.f); +} + +#pragma mark - Properties + +- (void)setProgress:(float)progress { + if (progress != _progress) { + _progress = progress; + [self setNeedsDisplay]; + } +} + +- (void)setProgressTintColor:(UIColor *)progressTintColor { + NSAssert(progressTintColor, @"The color should not be nil."); + if (progressTintColor != _progressTintColor && ![progressTintColor isEqual:_progressTintColor]) { + _progressTintColor = progressTintColor; + [self setNeedsDisplay]; + } +} + +- (void)setBackgroundTintColor:(UIColor *)backgroundTintColor { + NSAssert(backgroundTintColor, @"The color should not be nil."); + if (backgroundTintColor != _backgroundTintColor && ![backgroundTintColor isEqual:_backgroundTintColor]) { + _backgroundTintColor = backgroundTintColor; + [self setNeedsDisplay]; + } +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect { + CGContextRef context = UIGraphicsGetCurrentContext(); + + if (_annular) { + // Draw background + CGFloat lineWidth = 2.f; + UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath]; + processBackgroundPath.lineWidth = lineWidth; + processBackgroundPath.lineCapStyle = kCGLineCapButt; + CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); + CGFloat radius = (self.bounds.size.width - lineWidth)/2; + CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees + CGFloat endAngle = (2 * (float)M_PI) + startAngle; + [processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; + [_backgroundTintColor set]; + [processBackgroundPath stroke]; + // Draw progress + UIBezierPath *processPath = [UIBezierPath bezierPath]; + processPath.lineCapStyle = kCGLineCapSquare; + processPath.lineWidth = lineWidth; + endAngle = (self.progress * 2 * (float)M_PI) + startAngle; + [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; + [_progressTintColor set]; + [processPath stroke]; + } else { + // Draw background + CGFloat lineWidth = 2.f; + CGRect allRect = self.bounds; + CGRect circleRect = CGRectInset(allRect, lineWidth/2.f, lineWidth/2.f); + CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); + [_progressTintColor setStroke]; + [_backgroundTintColor setFill]; + CGContextSetLineWidth(context, lineWidth); + CGContextStrokeEllipseInRect(context, circleRect); + // 90 degrees + CGFloat startAngle = - ((float)M_PI / 2.f); + // Draw progress + UIBezierPath *processPath = [UIBezierPath bezierPath]; + processPath.lineCapStyle = kCGLineCapButt; + processPath.lineWidth = lineWidth * 2.f; + CGFloat radius = (CGRectGetWidth(self.bounds) / 2.f) - (processPath.lineWidth / 2.f); + CGFloat endAngle = (self.progress * 2.f * (float)M_PI) + startAngle; + [processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES]; + // Ensure that we don't get color overlapping when _progressTintColor alpha < 1.f. + CGContextSetBlendMode(context, kCGBlendModeCopy); + [_progressTintColor set]; + [processPath stroke]; + } +} + +@end + + +@implementation MBBarProgressView + +#pragma mark - Lifecycle + +- (id)init { + return [self initWithFrame:CGRectMake(.0f, .0f, 120.0f, 20.0f)]; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _progress = 0.f; + _lineColor = [UIColor whiteColor]; + _progressColor = [UIColor whiteColor]; + _progressRemainingColor = [UIColor clearColor]; + self.backgroundColor = [UIColor clearColor]; + self.opaque = NO; + } + return self; +} + +#pragma mark - Layout + +- (CGSize)intrinsicContentSize { + return CGSizeMake(120.f, 10.f); +} + +#pragma mark - Properties + +- (void)setProgress:(float)progress { + if (progress != _progress) { + _progress = progress; + [self setNeedsDisplay]; + } +} + +- (void)setProgressColor:(UIColor *)progressColor { + NSAssert(progressColor, @"The color should not be nil."); + if (progressColor != _progressColor && ![progressColor isEqual:_progressColor]) { + _progressColor = progressColor; + [self setNeedsDisplay]; + } +} + +- (void)setProgressRemainingColor:(UIColor *)progressRemainingColor { + NSAssert(progressRemainingColor, @"The color should not be nil."); + if (progressRemainingColor != _progressRemainingColor && ![progressRemainingColor isEqual:_progressRemainingColor]) { + _progressRemainingColor = progressRemainingColor; + [self setNeedsDisplay]; + } +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect { + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextSetLineWidth(context, 2); + CGContextSetStrokeColorWithColor(context,[_lineColor CGColor]); + CGContextSetFillColorWithColor(context, [_progressRemainingColor CGColor]); + + // Draw background and Border + CGFloat radius = (rect.size.height / 2) - 2; + CGContextMoveToPoint(context, 2, rect.size.height/2); + CGContextAddArcToPoint(context, 2, 2, radius + 2, 2, radius); + CGContextAddArcToPoint(context, rect.size.width - 2, 2, rect.size.width - 2, rect.size.height / 2, radius); + CGContextAddArcToPoint(context, rect.size.width - 2, rect.size.height - 2, rect.size.width - radius - 2, rect.size.height - 2, radius); + CGContextAddArcToPoint(context, 2, rect.size.height - 2, 2, rect.size.height/2, radius); + CGContextDrawPath(context, kCGPathFillStroke); + + CGContextSetFillColorWithColor(context, [_progressColor CGColor]); + radius = radius - 2; + CGFloat amount = self.progress * rect.size.width; + + // Progress in the middle area + if (amount >= radius + 4 && amount <= (rect.size.width - radius - 4)) { + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); + CGContextAddLineToPoint(context, amount, 4); + CGContextAddLineToPoint(context, amount, radius + 4); + + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); + CGContextAddLineToPoint(context, amount, rect.size.height - 4); + CGContextAddLineToPoint(context, amount, radius + 4); + + CGContextFillPath(context); + } + + // Progress in the right arc + else if (amount > radius + 4) { + CGFloat x = amount - (rect.size.width - radius - 4); + + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); + CGContextAddLineToPoint(context, rect.size.width - radius - 4, 4); + CGFloat angle = -acos(x/radius); + if (isnan(angle)) angle = 0; + CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, M_PI, angle, 0); + CGContextAddLineToPoint(context, amount, rect.size.height/2); + + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); + CGContextAddLineToPoint(context, rect.size.width - radius - 4, rect.size.height - 4); + angle = acos(x/radius); + if (isnan(angle)) angle = 0; + CGContextAddArc(context, rect.size.width - radius - 4, rect.size.height/2, radius, -M_PI, angle, 1); + CGContextAddLineToPoint(context, amount, rect.size.height/2); + + CGContextFillPath(context); + } + + // Progress is in the left arc + else if (amount < radius + 4 && amount > 0) { + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, 4, radius + 4, 4, radius); + CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); + + CGContextMoveToPoint(context, 4, rect.size.height/2); + CGContextAddArcToPoint(context, 4, rect.size.height - 4, radius + 4, rect.size.height - 4, radius); + CGContextAddLineToPoint(context, radius + 4, rect.size.height/2); + + CGContextFillPath(context); + } +} + +@end + + +@interface MBBackgroundView () + +@property UIVisualEffectView *effectView; + +@end + + +@implementation MBBackgroundView + +#pragma mark - Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + _style = MBProgressHUDBackgroundStyleBlur; + if (@available(iOS 13.0, *)) { + #if TARGET_OS_TV + _blurEffectStyle = UIBlurEffectStyleRegular; + #else + _blurEffectStyle = UIBlurEffectStyleSystemThickMaterial; + #endif + // Leaving the color unassigned yields best results. + } else { + _blurEffectStyle = UIBlurEffectStyleLight; + _color = [UIColor colorWithWhite:0.8f alpha:0.6f]; + } + + self.clipsToBounds = YES; + + [self updateForBackgroundStyle]; + } + return self; +} + +#pragma mark - Layout + +- (CGSize)intrinsicContentSize { + // Smallest size possible. Content pushes against this. + return CGSizeZero; +} + +#pragma mark - Appearance + +- (void)setStyle:(MBProgressHUDBackgroundStyle)style { + if (_style != style) { + _style = style; + [self updateForBackgroundStyle]; + } +} + +- (void)setColor:(UIColor *)color { + NSAssert(color, @"The color should not be nil."); + if (color != _color && ![color isEqual:_color]) { + _color = color; + [self updateViewsForColor:color]; + } +} + +- (void)setBlurEffectStyle:(UIBlurEffectStyle)blurEffectStyle { + if (_blurEffectStyle == blurEffectStyle) { + return; + } + + _blurEffectStyle = blurEffectStyle; + + [self updateForBackgroundStyle]; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Views + +- (void)updateForBackgroundStyle { + [self.effectView removeFromSuperview]; + self.effectView = nil; + + MBProgressHUDBackgroundStyle style = self.style; + if (style == MBProgressHUDBackgroundStyleBlur) { + UIBlurEffect *effect = [UIBlurEffect effectWithStyle:self.blurEffectStyle]; + UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:effect]; + [self insertSubview:effectView atIndex:0]; + effectView.frame = self.bounds; + effectView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + self.backgroundColor = self.color; + self.layer.allowsGroupOpacity = NO; + self.effectView = effectView; + } else { + self.backgroundColor = self.color; + } +} + +- (void)updateViewsForColor:(UIColor *)color { + if (self.style == MBProgressHUDBackgroundStyleBlur) { + self.backgroundColor = self.color; + } else { + self.backgroundColor = self.color; + } +} + +@end + + +@implementation MBProgressHUDRoundedButton + +#pragma mark - Lifecycle + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + CALayer *layer = self.layer; + layer.borderWidth = 1.f; + } + return self; +} + +#pragma mark - Layout + +- (void)layoutSubviews { + [super layoutSubviews]; + // Fully rounded corners + CGFloat height = CGRectGetHeight(self.bounds); + self.layer.cornerRadius = ceil(height / 2.f); +} + +- (CGSize)intrinsicContentSize { + // Only show if we have associated control events and a title + if ((self.allControlEvents == 0) || ([self titleForState:UIControlStateNormal].length == 0)) + return CGSizeZero; + CGSize size = [super intrinsicContentSize]; + // Add some side padding + size.width += 20.f; + return size; +} + +#pragma mark - Color + +- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state { + [super setTitleColor:color forState:state]; + // Update related colors + [self setHighlighted:self.highlighted]; + self.layer.borderColor = color.CGColor; +} + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + UIColor *baseColor = [self titleColorForState:UIControlStateSelected]; + self.backgroundColor = highlighted ? [baseColor colorWithAlphaComponent:0.1f] : [UIColor clearColor]; +} + +@end diff --git a/Pods/MBProgressHUD/README.mdown b/Pods/MBProgressHUD/README.mdown new file mode 100644 index 0000000..c90f5c6 --- /dev/null +++ b/Pods/MBProgressHUD/README.mdown @@ -0,0 +1,138 @@ +# MBProgressHUD + +[![Build Status](https://travis-ci.org/matej/MBProgressHUD.svg?branch=master)](https://travis-ci.org/matej/MBProgressHUD) [![codecov.io](https://codecov.io/github/matej/MBProgressHUD/coverage.svg?branch=master)](https://codecov.io/github/matej/MBProgressHUD?branch=master) + [![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application) [![Accio supported](https://img.shields.io/badge/Accio-supported-0A7CF5.svg?style=flat)](https://github.com/JamitLabs/Accio) [![CocoaPods compatible](https://img.shields.io/cocoapods/v/MBProgressHUD.svg?style=flat)](https://cocoapods.org/pods/MBProgressHUD) [![License: MIT](https://img.shields.io/cocoapods/l/MBProgressHUD.svg?style=flat)](http://opensource.org/licenses/MIT) + +`MBProgressHUD` is an iOS drop-in class that displays a translucent HUD with an indicator and/or labels while work is being done in a background thread. The HUD is meant as a replacement for the undocumented, private `UIKit` `UIProgressHUD` with some additional features. + +[![](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/1-small.png)](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/1.png) +[![](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/2-small.png)](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/2.png) +[![](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/3-small.png)](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/3.png) +[![](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/4-small.png)](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/4.png) +[![](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/5-small.png)](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/5.png) +[![](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/6-small.png)](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/6.png) +[![](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/7-small.png)](https://raw.githubusercontent.com/wiki/matej/MBProgressHUD/Screenshots/7.png) + +**NOTE:** The class has recently undergone a major rewrite. The old version is available in the [legacy](https://github.com/jdg/MBProgressHUD/tree/legacy) branch, should you need it. + +## Requirements + +`MBProgressHUD` works on iOS 9.0+. It depends on the following Apple frameworks, which should already be included with most Xcode templates: + +* Foundation.framework +* UIKit.framework +* CoreGraphics.framework + +You will need the latest developer tools in order to build `MBProgressHUD`. Old Xcode versions might work, but compatibility will not be explicitly maintained. + +## Adding MBProgressHUD to your project + +### CocoaPods + +[CocoaPods](http://cocoapods.org) is the recommended way to add MBProgressHUD to your project. + +1. Add a pod entry for MBProgressHUD to your Podfile `pod 'MBProgressHUD', '~> 1.2.0'` +2. Install the pod(s) by running `pod install`. +3. Include MBProgressHUD wherever you need it with `#import "MBProgressHUD.h"`. + +### Carthage + +1. Add MBProgressHUD to your Cartfile. e.g., `github "jdg/MBProgressHUD" ~> 1.2.0` +2. Run `carthage update` +3. Follow the rest of the [standard Carthage installation instructions](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application) to add MBProgressHUD to your project. + +### SwiftPM / Accio + +1. Add the following to your `Package.swift`: + ```swift + .package(url: "https://github.com/jdg/MBProgressHUD.git", .upToNextMajor(from: "1.2.0")), + ``` +2. Next, add `MBProgressHUD` to your App targets dependencies like so: + ```swift + .target(name: "App", dependencies: ["MBProgressHUD"]), + ``` +3. Then open your project in Xcode 11+ (SwiftPM) or run `accio update` (Accio). + +### Source files + +Alternatively you can directly add the `MBProgressHUD.h` and `MBProgressHUD.m` source files to your project. + +1. Download the [latest code version](https://github.com/matej/MBProgressHUD/archive/master.zip) or add the repository as a git submodule to your git-tracked project. +2. Open your project in Xcode, then drag and drop `MBProgressHUD.h` and `MBProgressHUD.m` onto your project (use the "Product Navigator view"). Make sure to select Copy items when asked if you extracted the code archive outside of your project. +3. Include MBProgressHUD wherever you need it with `#import "MBProgressHUD.h"`. + +### Static library + +You can also add MBProgressHUD as a static library to your project or workspace. + +1. Download the [latest code version](https://github.com/matej/MBProgressHUD/downloads) or add the repository as a git submodule to your git-tracked project. +2. Open your project in Xcode, then drag and drop `MBProgressHUD.xcodeproj` onto your project or workspace (use the "Product Navigator view"). +3. Select your target and go to the Build phases tab. In the Link Binary With Libraries section select the add button. On the sheet find and add `libMBProgressHUD.a`. You might also need to add `MBProgressHUD` to the Target Dependencies list. +4. Include MBProgressHUD wherever you need it with `#import `. + +## Usage + +The main guideline you need to follow when dealing with MBProgressHUD while running long-running tasks is keeping the main thread work-free, so the UI can be updated promptly. The recommended way of using MBProgressHUD is therefore to set it up on the main thread and then spinning the task, that you want to perform, off onto a new thread. + +```objective-c +[MBProgressHUD showHUDAddedTo:self.view animated:YES]; +dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ + // Do something... + dispatch_async(dispatch_get_main_queue(), ^{ + [MBProgressHUD hideHUDForView:self.view animated:YES]; + }); +}); +``` + +You can add the HUD on any view or window. It is however a good idea to avoid adding the HUD to certain `UIKit` views with complex view hierarchies - like `UITableView` or `UICollectionView`. Those can mutate their subviews in unexpected ways and thereby break HUD display. + +If you need to configure the HUD you can do this by using the MBProgressHUD reference that showHUDAddedTo:animated: returns. + +```objective-c +MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; +hud.mode = MBProgressHUDModeAnnularDeterminate; +hud.label.text = @"Loading"; +[self doSomethingInBackgroundWithProgressCallback:^(float progress) { + hud.progress = progress; +} completionCallback:^{ + [hud hideAnimated:YES]; +}]; +``` + +You can also use a `NSProgress` object and MBProgressHUD will update itself when there is progress reported through that object. + +```objective-c +MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; +hud.mode = MBProgressHUDModeAnnularDeterminate; +hud.label.text = @"Loading"; +NSProgress *progress = [self doSomethingInBackgroundCompletion:^{ + [hud hideAnimated:YES]; +}]; +hud.progressObject = progress; +``` + +Keep in mind that UI updates, inclining calls to MBProgressHUD should always be done on the main thread. + +If you need to run your long-running task in the main thread, you should perform it with a slight delay, so UIKit will have enough time to update the UI (i.e., draw the HUD) before you block the main thread with your task. + +```objective-c +[MBProgressHUD showHUDAddedTo:self.view animated:YES]; +dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC); +dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + // Do something... + [MBProgressHUD hideHUDForView:self.view animated:YES]; +}); +``` + +You should be aware that any HUD updates issued inside the above block won't be displayed until the block completes. + +For more examples, including how to use MBProgressHUD with asynchronous operations such as NSURLConnection, take a look at the bundled demo project. Extensive API documentation is provided in the header file (MBProgressHUD.h). + + +## License + +This code is distributed under the terms and conditions of the [MIT license](LICENSE). + +## Change-log + +A brief summary of each MBProgressHUD release can be found in the [CHANGELOG](CHANGELOG.mdown). diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index 61ce333..28cb1e8 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -1,11 +1,11 @@ PODS: - - Bolts/Tasks (1.8.4) - - FastCoding (3.2.2) + - Bolts-Swift (1.5.0) - FlexColorPicker (1.4.4) - MBProgressHUD (1.2.0) - - MetaWearPrivate (2.10.0): - - Bolts/Tasks (~> 1.8.4) - - FastCoding (~> 3.2.2) + - MetaWear (4.1.3): + - MetaWear/Core (= 4.1.3) + - MetaWear/Core (4.1.3): + - Bolts-Swift (~> 1) - PRTween (0.1.0) - SQLite.swift (0.11.6): - SQLite.swift/standard (= 0.11.6) @@ -15,41 +15,30 @@ PODS: DEPENDENCIES: - FlexColorPicker - MBProgressHUD - - MetaWearPrivate (from `https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS.git`, commit `1254b54`) + - MetaWear - PRTween (~> 0.1) - SQLite.swift (~> 0.11.5) - StaticDataTableViewController SPEC REPOS: trunk: - - Bolts - - FastCoding + - Bolts-Swift - FlexColorPicker - MBProgressHUD + - MetaWear - PRTween - SQLite.swift - StaticDataTableViewController -EXTERNAL SOURCES: - MetaWearPrivate: - :commit: 1254b54 - :git: https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS.git - -CHECKOUT OPTIONS: - MetaWearPrivate: - :commit: 1254b54 - :git: https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS.git - SPEC CHECKSUMS: - Bolts: 8a7995239dbe724f9cba2248b766d48b7ebdd322 - FastCoding: f7b1b75a2ccb0dd6ef9c928e46339e20252d98d3 + Bolts-Swift: afbbaf8c8186e7f769be4afa656949c14087ba44 FlexColorPicker: ce72e0a9e0870815a0beba419ac3e09913401624 MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406 - MetaWearPrivate: f9cb466d358f6a4a5639f3cce393ddaf37c4def5 + MetaWear: 172042a920e6853083f1fd94fb4f509016188586 PRTween: 6c58c7e32ebcf31e33e6a6e6bc727ebef3b668ef SQLite.swift: 46d890be8601964454bd3392527f863d1b802d45 StaticDataTableViewController: 0c5c4a47861446dd3cfd52530ae801ec7662ce26 -PODFILE CHECKSUM: 010e7e706eb37c9ef154fb2e9dd3e9eecd5cba8f +PODFILE CHECKSUM: 16aec52e84a0b81c82c2e4b53a90b7147cf33fb1 COCOAPODS: 1.15.2 diff --git a/Pods/MetaWear/LICENSE.md b/Pods/MetaWear/LICENSE.md new file mode 100644 index 0000000..786ef0a --- /dev/null +++ b/Pods/MetaWear/LICENSE.md @@ -0,0 +1,10 @@ +Copyright 2021 MbientLab Inc. All rights reserved. + +IMPORTANT: Your use of this Software is limited to those specific rights granted under the terms of a software license agreement between the user who downloaded the software, his/her employer (which must be your employer) and MbientLab Inc, (the "License"). +You may not use this Software unless you agree to abide by the terms of the License which can be found at www.mbientlab.com/terms. +The License limits your use, and you acknowledge, that the Software may be modified, copied, and distributed when used in conjunction with an MbientLab Inc, product. +Other than for the foregoing purpose, you may not use, reproduce, copy, prepare derivative works of, modify, distribute, perform, display or sell this Software and/or its documentation for any purpose. + +YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + +Should you have any questions regarding your right to use this Software, contact MbientLab via email: hello@mbientlab.com. diff --git a/Pods/MetaWear/MetaWear/Core/Bridging.swift b/Pods/MetaWear/MetaWear/Core/Bridging.swift new file mode 100644 index 0000000..44e46d0 --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/Bridging.swift @@ -0,0 +1,57 @@ +/** + * Bridging.swift + * MetaWear-Swift + * + * Created by Stephen Schiffli on 12/14/17. + * Copyright 2017 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + + +/// Convert to void* without ownership, only use when lifetime +/// of object is guaranteed elsewhere +public func bridge(obj: T) -> UnsafeMutableRawPointer { + return Unmanaged.passUnretained(obj).toOpaque() +} +/// Convert from void* without ownership, only use when lifetime +/// of object is guaranteed elsewhere +public func bridge(ptr: UnsafeRawPointer) -> T { + return Unmanaged.fromOpaque(ptr).takeUnretainedValue() +} + +/// Convert to void* with ownership, make sure these are always +/// called in matching pairs with bridgeTransfer +public func bridgeRetained(obj: T) -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(obj).toOpaque() +} +/// Convert from void* with ownership, make sure these are always +/// called in matching pairs with bridgeRetained +public func bridgeTransfer(ptr: UnsafeRawPointer) -> T { + return Unmanaged.fromOpaque(ptr).takeRetainedValue() +} diff --git a/Pods/MetaWear/MetaWear/Core/CBUUID.swift b/Pods/MetaWear/MetaWear/Core/CBUUID.swift new file mode 100644 index 0000000..3d4721e --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/CBUUID.swift @@ -0,0 +1,52 @@ +/** + * CBUUID.swift + * MetaWear-Swift + * + * Created by Stephen Schiffli on 12/14/17. + * Copyright 2017 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + +import CoreBluetooth + +/// Bluetooth ID's used by MetaWear +extension CBUUID { + public static let metaWearService = CBUUID(string: "326A9000-85CB-9195-D9DD-464CFBBAE75A") + public static let metaWearCommand = CBUUID(string: "326A9001-85CB-9195-D9DD-464CFBBAE75A") + public static let metaWearNotification = CBUUID(string: "326A9006-85CB-9195-D9DD-464CFBBAE75A") + public static let metaWearDfuService = CBUUID(string: "00001530-1212-EFDE-1523-785FEABCD123") + public static let batteryService = CBUUID(string: "180F") + public static let batteryLife = CBUUID(string: "2A19") + public static let disService = CBUUID(string: "180A") + public static let disModelNumber = CBUUID(string: "2A24") + public static let disSerialNumber = CBUUID(string: "2A25") + public static let disFirmwareRev = CBUUID(string: "2A26") + public static let disHardwareRev = CBUUID(string: "2A27") + public static let disManufacturerName = CBUUID(string: "2A29") +} diff --git a/Pods/MetaWear/MetaWear/Core/DeviceInformation.swift b/Pods/MetaWear/MetaWear/Core/DeviceInformation.swift new file mode 100644 index 0000000..1cd1602 --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/DeviceInformation.swift @@ -0,0 +1,68 @@ +/** + * DeviceInformation.swift + * MetaWear + * + * Created by Stephen Schiffli on 5/3/18. + * Copyright 2018 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + +import MetaWearCpp + +/// Container of information about a MetaWear board +public struct DeviceInformation { + public let manufacturer: String + public let modelNumber: String + public let serialNumber: String + public let firmwareRevision: String + public let hardwareRevision: String + + public init(manufacturer: String, + modelNumber: String, + serialNumber: String, + firmwareRevision: String, + hardwareRevision: String) { + self.manufacturer = manufacturer + self.modelNumber = modelNumber + self.serialNumber = serialNumber + self.firmwareRevision = firmwareRevision + self.hardwareRevision = hardwareRevision + } +} + +extension MblMwDeviceInformation { + /// Used to bridge between MetaWearCpp classes and native managed Swift struct + func convert() -> DeviceInformation { + return DeviceInformation(manufacturer: String(cString: manufacturer), + modelNumber: String(cString: model_number), + serialNumber: String(cString: serial_number), + firmwareRevision: String(cString: firmware_revision), + hardwareRevision: String(cString: hardware_revision)) + } +} diff --git a/Pods/MetaWear/MetaWear/Core/LogDelegate.swift b/Pods/MetaWear/MetaWear/Core/LogDelegate.swift new file mode 100644 index 0000000..1d192ac --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/LogDelegate.swift @@ -0,0 +1,73 @@ +/** + * LogDelegate.swift + * MetaWear-Swift + * + * Created by Stephen Schiffli on 12/14/17. + * Copyright 2017 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + +/// Handle messages from MetaWear devices +public protocol LogDelegate { + func logWith(_ level: LogLevel, message: String) +} + +/// The verbosity of log messages +public enum LogLevel: Int { + case debug = 0 + case info = 1 + case warning = 2 + case error = 3 + + var name: String { + switch self { + case .debug: + return "debug" + case .info: + return "info" + case .warning: + return "warning" + case .error: + return "error" + } + } +} + +/// Simple logger implementation that prints messagse to the console +public struct ConsoleLogger: LogDelegate { + public static let shared = ConsoleLogger() + + public var minLevel = LogLevel.info + public func logWith(_ level: LogLevel, message: String) { + guard level.rawValue >= minLevel.rawValue else { + return + } + print("\(level) \(message)") + } +} diff --git a/Pods/MetaWear/MetaWear/Core/MblMwGattChar.swift b/Pods/MetaWear/MetaWear/Core/MblMwGattChar.swift new file mode 100644 index 0000000..7d8a3fc --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/MblMwGattChar.swift @@ -0,0 +1,68 @@ +/** + * MblMwGattChar.swift + * MetaWear-Swift + * + * Created by Stephen Schiffli on 12/14/17. + * Copyright 2017 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + +import CoreBluetooth +import MetaWearCpp + + +/// Helpers for dealing with the C++ version of GATT Service/Characteristic +extension MblMwGattChar: Hashable { + var serviceUUID: CBUUID { + var service_uuid_high_swap = service_uuid_high.byteSwapped + var data = Data(buffer: UnsafeBufferPointer(start: &service_uuid_high_swap, count: 1)) + var service_uuid_low_swap = service_uuid_low.byteSwapped + data.append(UnsafeBufferPointer(start: &service_uuid_low_swap, count: 1)) + return CBUUID(data: data) + } + var characteristicUUID: CBUUID { + var uuid_high_swap = uuid_high.byteSwapped + var data = Data(buffer: UnsafeBufferPointer(start: &uuid_high_swap, count: 1)) + var uuid_low_swap = uuid_low.byteSwapped + data.append(UnsafeBufferPointer(start: &uuid_low_swap, count: 1)) + return CBUUID(data: data) + } + public func hash(into hasher: inout Hasher) { + hasher.combine(service_uuid_high) + hasher.combine(service_uuid_low) + hasher.combine(uuid_high) + hasher.combine(uuid_low) + } + public static func ==(lhs: MblMwGattChar, rhs: MblMwGattChar) -> Bool { + return lhs.service_uuid_high == rhs.service_uuid_high && + lhs.service_uuid_low == rhs.service_uuid_low && + lhs.uuid_high == rhs.uuid_high && + lhs.uuid_low == rhs.uuid_low + } +} diff --git a/Pods/MetaWear/MetaWear/Core/MetaWear.swift b/Pods/MetaWear/MetaWear/Core/MetaWear.swift new file mode 100644 index 0000000..904fffc --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/MetaWear.swift @@ -0,0 +1,640 @@ +/** + * MetaWear.swift + * MetaWear-Swift + * + * Created by Stephen Schiffli on 12/14/17. + * Copyright 2017 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + +import CoreBluetooth +import MetaWearCpp +import BoltsSwift + +/// Possible error's from MetaWear operations +public enum MetaWearError: Error { + /// Generic failure, see message for details + case operationFailed(message: String) + case bluetoothUnsupported + case bluetoothUnauthorized + case bluetoothPoweredOff +} + +extension MetaWearError: LocalizedError { + public var errorDescription: String? { + switch self { + case .operationFailed(let message): + return "Operation failed: \(message)" + case .bluetoothUnsupported: + return "Bluetooth unsupported on this platform" + case .bluetoothUnauthorized: + return "Bluetooth unauthorized in this App" + case .bluetoothPoweredOff: + return "Bluetooth powered off" + } + } +} + +/// Folder to store device information +fileprivate let appSupportDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first! +fileprivate let adQueue = DispatchQueue(label: "com.mbientlab.adQueue") + + +/// Each MetaWear object corresponds a physical MetaWear board. It contains +/// methods for connecting, disconnecting, saving and restoring state. +public class MetaWear: NSObject { + /// Assign a delegate to receive information about what the device is doing + public var logDelegate: LogDelegate? + /// The corresponding CoreBluetooth object + public let peripheral: CBPeripheral + /// The scanner that disovered this device + public private(set) weak var scanner: MetaWearScanner? + /// This is passed to MetaWearCpp functions + public private(set) var board: OpaquePointer! + /// Data from the advertisement packet + /// This is continually updated when the scanner is active + public var advertisementData: [String : Any] { + get { + return adQueue.sync { advertisementDataImpl } + } + } + /// Received signal strength indicator + /// This is continually updated when the scanner is active + public private(set) var rssi: Int = 0 + /// Callback block invoked each advertisementData and rssi is updated + public var advertisementReceived: (() -> Void)? + /// MAC address of the device, available only after you have connected once + public internal(set) var mac: String? + /// Details about the device, available only after you have connected once + public internal(set) var info: DeviceInformation? + /// Indication that the BLE link is connected and the MetaWearCpp library is properly initialized + public private(set) var isConnectedAndSetup = false + /// Check if this advertised or discovered as a MetaBoot + public private(set) var isMetaBoot = false + /// Get the most update to date name of the device + /// - Note: + /// peripheral.name may be cached, use the name from advertising data + public var name: String { + return adQueue.sync { + let adName = advertisementDataImpl[CBAdvertisementDataLocalNameKey] as? String + return adName ?? peripheral.name ?? "MetaWear" + } + } + /// Helper utility create a file name specifically for this device + public var uniqueUrl: URL { + var url = appSupportDirectory.appendingPathComponent("com.mbientlab.devices", isDirectory: true) + try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: true) + url.appendPathComponent(peripheral.identifier.uuidString + ".file") + return url + } + /// In order to ensure crash free behavior of the MetaWearCpp library, all calls into + /// it should occur from this queue + public var apiAccessQueue: DispatchQueue { + return scanner?.bleQueue ?? DispatchQueue.global() + } + /// Bolts-Swift shortcut to apiAccessQueue + public var apiAccessExecutor: Executor { + return Executor.queue(apiAccessQueue) + } + /// Smooth out the RSSI into something less jumpy + public func averageRSSI(lastNSeconds: Double = 5.0) -> Double? { + return adQueue.sync { + let filteredRSSI = rssiHistory.filter { -$0.0.timeIntervalSinceNow < lastNSeconds } + guard filteredRSSI.count > 0 else { + return nil + } + let sumArray = filteredRSSI.reduce(0.0) { $0 + $1.1 } + return sumArray / Double(filteredRSSI.count) + } + } + + /// Connect to the device and initialize the MetaWearCpp libray + /// - Returns: Task that completes when the device disconnects + public func connectAndSetup() -> Task> { + let source = TaskCompletionSource>() + apiAccessQueue.async { + guard !self.isConnectedAndSetup else { + let disconnectSource = TaskCompletionSource() + self.disconnectionSources.append(disconnectSource) + source.trySet(result: disconnectSource.task) + return + } + self.connectionSources.append(source) + if self.connectionSources.count == 1 { + self.scanner?.connect(self) + } + } + return source.task + } + /// Disconnect or cancel a connection attempt + public func cancelConnection() { + scanner?.cancelConnection(self) + } + /// Retrieves the current RSSI value for the peripheral while it is connected + public func readRSSI() -> Task { + let source = TaskCompletionSource() + apiAccessQueue.async { + guard self.peripheral.state == .connected else { + source.trySet(error: MetaWearError.operationFailed(message: "MetaWear not connected, can't perform operation. Please connect to MetaWear before reading RSSI.")) + return + } + self.rssiSources.append(source) + self.peripheral.readRSSI() + } + return source.task + } + + /// Add this to a persistent list retrieved with `MetaWearScanner.retrieveSavedMetaWearsAsync(...)` + public func remember() { + scanner?.remember(self) + } + /// Remove this from the persistent list `MetaWearScanner.retrieveSavedMetaWearsAsync(...)` + public func forget() { + scanner?.forget(self) + } + /// Dump all MetaWearCpp libray state + public func serialize() -> [UInt8] { + var count: UInt32 = 0 + let start = mbl_mw_metawearboard_serialize(board, &count) + let data = Array(UnsafeBufferPointer(start: start, count: Int(count))) + mbl_mw_memory_free(start) + return data + } + /// Restore MetaWearCpp libray state, must be called before `connectAndSetup()` + public func deserialize(_ _data: [UInt8]) { + var data = _data + mbl_mw_metawearboard_deserialize(board, &data, UInt32(data.count)) + } + + public func readHardwareRev() -> Task { + return readCharacteristic(.disService, .disHardwareRev).continueOnSuccessWith { + return String(data: $0, encoding: .utf8) ?? "" + } + } + + public func readModelNumber() -> Task { + return readCharacteristic(.disService, .disModelNumber).continueOnSuccessWith { + return String(data: $0, encoding: .utf8) ?? "" + } + } + + public func readFirmwareRev() -> Task { + return readCharacteristic(.disService, .disFirmwareRev).continueOnSuccessWith { + return String(data: $0, encoding: .utf8) ?? "" + } + } + + public func readSerialNumber() -> Task { + return readCharacteristic(.disService, .disSerialNumber).continueOnSuccessWith { + return String(data: $0, encoding: .utf8) ?? "" + } + } + + public func readManufacturer() -> Task { + return readCharacteristic(.disService, .disManufacturerName).continueOnSuccessWith { + return String(data: $0, encoding: .utf8) ?? "" + } + } + + public func getCharacteristic(_ serviceUUID: CBUUID, + _ characteristicUUID: CBUUID) -> (error: Error?, characteristic: CBCharacteristic?) { + guard let service = self.peripheral.services?.first(where: { $0.uuid == serviceUUID }) else { + return (MetaWearError.operationFailed(message: "service not found"), nil) + } + guard let characteristic = service.characteristics?.first(where: { $0.uuid == characteristicUUID }) else { + return (MetaWearError.operationFailed(message: "characteristics not found"), nil) + } + return (nil, characteristic) + } + + public func readCharacteristic(_ serviceUUID: CBUUID, _ characteristicUUID: CBUUID) -> Task { + let source = TaskCompletionSource() + apiAccessQueue.async { + let result = self.getCharacteristic(serviceUUID, characteristicUUID) + guard let characteristic = result.characteristic else { + source.trySet(error: result.error!) + return + } + var tmp = self.localReadCallbacks[characteristic] ?? [] + tmp.append(source) + self.localReadCallbacks[characteristic] = tmp + self.peripheral.readValue(for: characteristic) + } + return source.task + } + + /// Internal details below + fileprivate var gattCharMap: [MblMwGattChar: CBCharacteristic] = [:] + fileprivate var subscribeCompleteCallbacks: [CBCharacteristic: MblMwFnVoidVoidPtrInt] = [:] + fileprivate var onDataCallbacks: [CBCharacteristic: MblMwFnIntVoidPtrArray] = [:] + fileprivate var onReadCallbacks: [CBCharacteristic: MblMwFnIntVoidPtrArray] = [:] + fileprivate var onDisconnectCallback: MblMwFnVoidVoidPtrInt? + fileprivate var disconnectionSources: [TaskCompletionSource] = [] + fileprivate var connectionSources: [TaskCompletionSource>] = [] + fileprivate var rssiSources: [TaskCompletionSource] = [] + fileprivate var localReadCallbacks: [CBCharacteristic: [TaskCompletionSource]] = [:] + fileprivate var advertisementDataImpl: [String : Any] = [:] + fileprivate var writeQueue: [(data: Data, characteristic: CBCharacteristic, type: CBCharacteristicWriteType)] = [] + fileprivate var commandCount = 0 + + fileprivate var serviceCount = 0 + var rssiHistory: [(Date, Double)] = [] + + init(peripheral: CBPeripheral, scanner: MetaWearScanner) { + self.peripheral = peripheral + self.scanner = scanner + super.init() + self.peripheral.delegate = self + var connection = MblMwBtleConnection(context: bridge(obj: self), + write_gatt_char: writeGattChar, + read_gatt_char: readGattChar, + enable_notifications: enableNotifications, + on_disconnect: onDisconnect) + self.board = mbl_mw_metawearboard_create(&connection) + // TODO: evaluate if the timeout provides value + mbl_mw_metawearboard_set_time_for_response(self.board, 0) + self.mac = UserDefaults.standard.string(forKey: "com.mbientlab.macstorage." + peripheral.identifier.uuidString) + } + + func didDiscover(advertisementData: [String : Any], rssi RSSI: NSNumber) { + adQueue.sync { + self.advertisementDataImpl = advertisementData + if let services = advertisementData[CBAdvertisementDataServiceUUIDsKey] as? [CBUUID] { + self.isMetaBoot = services.contains(.metaWearDfuService) + } + self.rssi = RSSI.intValue + // Timestamp and save the last N RSSI samples + let rssi = RSSI.doubleValue + if rssi < 0 { + rssiHistory.insert((Date(), RSSI.doubleValue), at: 0) + } + if rssiHistory.count > 10 { + rssiHistory.removeLast() + } + } + advertisementReceived?() + + logDelegate?.logWith(.info, message: "didDiscover: \(RSSI)") + } + + func didConnect() { + // Perform a service discovery and setup + peripheral.discoverServices([ + .metaWearService, + .metaWearDfuService, + .batteryService, + .disService + ]) + + logDelegate?.logWith(.info, message: "didConnect") + } + func didFailToConnect(error: Error?) { + invokeConnectionHandlers(error: error, cancelled: false) + invokeDisconnectionHandlers(error: error) + + logDelegate?.logWith(.info, message: "didFailToConnect: \(String(describing: error))") + } + func didDisconnectPeripheral(error: Error?) { + invokeConnectionHandlers(error: error, cancelled: error == nil) + invokeDisconnectionHandlers(error: error) + + logDelegate?.logWith(.info, message: "didDisconnectPeripheral: \(String(describing: error))") + } + func invokeDisconnectionHandlers(error: Error?) { + assert(DispatchQueue.isBleQueue) + isConnectedAndSetup = false + // Inform the C++ SDK + onDisconnectCallback?(UnsafeRawPointer(board), 0) + onDisconnectCallback = nil + + let unexpected = (error != nil) && (error as? CBError)?.code != .peripheralDisconnected + disconnectionSources.forEach { unexpected ? $0.set(error: error!) : $0.set(result: self) } + disconnectionSources.removeAll(keepingCapacity: true) + + gattCharMap = [:] + subscribeCompleteCallbacks = [:] + onDataCallbacks = [:] + onReadCallbacks = [:] + localReadCallbacks.forEach { $0.value.forEach { $0.trySet(error: MetaWearError.operationFailed(message: "disconnected before read finished")) } } + localReadCallbacks.removeAll(keepingCapacity: true) + writeQueue.removeAll() + commandCount = 0 + } + func invokeConnectionHandlers(error: Error?, cancelled: Bool) { + assert(DispatchQueue.isBleQueue) + if !cancelled && error == nil { + self.isConnectedAndSetup = true + } + // Clear out the connectionSources array now because we use the + // length as an indication of a pending operation, and if any of + // the callback call connectAndSetup, we need the right thing to happen + let localConnectionSources = connectionSources + connectionSources.removeAll(keepingCapacity: true) + + if let error = error { + localConnectionSources.forEach { $0.trySet(error: error) } + } else if cancelled { + localConnectionSources.forEach { $0.tryCancel() } + } else { + let source = TaskCompletionSource() + disconnectionSources.append(source) + localConnectionSources.forEach { $0.trySet(result: source.task) } + } + } + fileprivate func getCharacteristic(_ characteristicPtr: UnsafePointer?) -> CBCharacteristic? { + guard let characteristicPtr = characteristicPtr else { + return nil + } + if let characteristic = gattCharMap[characteristicPtr.pointee] { + return characteristic + } + + let serviceUUID = characteristicPtr.pointee.serviceUUID + let _service = peripheral.services?.first { service -> Bool in + return service.uuid == serviceUUID + } + guard let service = _service else { + return nil + } + + let characteristicUUID = characteristicPtr.pointee.characteristicUUID + let _characteristic = service.characteristics?.first { characteristic -> Bool in + return characteristic.uuid == characteristicUUID + } + guard let characteristic = _characteristic else { + return nil + } + + gattCharMap[characteristicPtr.pointee] = characteristic + return characteristic + } +} + +extension MetaWear: CBPeripheralDelegate { + public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { + // Abort the connection on any error here + guard error == nil else { + invokeConnectionHandlers(error: error!, cancelled: false) + cancelConnection() + return + } + + gattCharMap = [:] + serviceCount = 0 + for service in peripheral.services! { + switch service.uuid { + case .metaWearService: + isMetaBoot = false + peripheral.discoverCharacteristics([ + .metaWearCommand, + .metaWearNotification], for: service) + case .batteryService: + peripheral.discoverCharacteristics([.batteryLife], for: service) + case .disService: + peripheral.discoverCharacteristics( + [.disManufacturerName, + .disSerialNumber, + .disHardwareRev, + .disFirmwareRev, + .disModelNumber], for: service) + case .metaWearDfuService: + // Expected service, but we don't need to discover its characteristics + isMetaBoot = true + default: + let error = MetaWearError.operationFailed(message: "MetaWear device contained an unexpected BLE service. Please try connection again.") + self.invokeConnectionHandlers(error: error, cancelled: false) + self.invokeDisconnectionHandlers(error: error) + self.cancelConnection() + break + } + } + } + public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { + // Abort the connection on any error here + guard error == nil else { + invokeConnectionHandlers(error: error!, cancelled: false) + cancelConnection() + return + } + + guard !isMetaBoot else { + let task = Task.whenAllResult([readManufacturer(), readModelNumber(), readSerialNumber(), readFirmwareRev(), readHardwareRev()]) + task.continueWith(apiAccessExecutor) { + if let results = $0.result { + self.info = DeviceInformation(manufacturer: results[0], modelNumber: results[1], serialNumber: results[2], firmwareRevision: results[3], hardwareRevision: results[4]) + } + self.invokeConnectionHandlers(error: $0.error, cancelled: false) + } + return + } + serviceCount += 1 + if serviceCount == 3 { + // Setup the CPP SDK + mbl_mw_metawearboard_initialize(board, bridgeRetained(obj: self)) { (context, board, code) in + let device: MetaWear = bridgeTransfer(ptr: context!) + let error = code != 0 ? MetaWearError.operationFailed(message: "initialized failed: \(code)") : nil + // Finished if we had an error + guard error == nil else { + device.apiAccessQueue.async { + device.invokeConnectionHandlers(error: error, cancelled: false) + device.cancelConnection() + } + return + } + // Grab the device info + let rawInfo = mbl_mw_metawearboard_get_device_information(device.board) + device.info = rawInfo?.pointee.convert() + mbl_mw_memory_free(UnsafeMutableRawPointer(mutating: rawInfo)) + // Grab and cache the mac address if needed + var task = Task<()>(()) + if device.mac == nil, let signal = mbl_mw_settings_get_mac_data_signal(board) { + let source = TaskCompletionSource() + mbl_mw_datasignal_subscribe(signal, bridgeRetained(obj: source)) { (context, dataPtr) in + let source: TaskCompletionSource = bridgeTransfer(ptr: context!) + if let dataPtr = dataPtr { + source.set(result: dataPtr.pointee.valueAs()) + } else { + source.set(error: MetaWearError.operationFailed(message: "failed not read mac")) + } + } + mbl_mw_datasignal_read(signal) + task = source.task.continueWith { + mbl_mw_datasignal_unsubscribe(signal) + device.mac = $0.result + UserDefaults.standard.set(device.mac , forKey: "com.mbientlab.macstorage." + device.peripheral.identifier.uuidString) + } + } + // Finish off the connections + task.continueWith(device.apiAccessExecutor) { _ in + device.invokeConnectionHandlers(error: nil, cancelled: false) + } + } + } + } + public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { + guard error == nil else { + logDelegate?.logWith(.error, message: "didUpdateValueForCharacteristic \(error!)") + return + } + if characteristic.uuid == .metaWearNotification { + logDelegate?.logWith(.info, message: "Received: \(characteristic.value?.hexEncodedString() ?? "N/A")") + } else { + logDelegate?.logWith(.info, message: "didUpdateValueForCharacteristic \(characteristic)") + } + guard let data = characteristic.value, data.count > 0 else { + return + } + if let onRead = onReadCallbacks[characteristic] { + data.withUnsafeBytes { rawBufferPointer -> Void in + let unsafeBufferPointer = rawBufferPointer.bindMemory(to: UInt8.self) + let unsafePointer = unsafeBufferPointer.baseAddress! + let _ = onRead(UnsafeRawPointer(board), unsafePointer, UInt8(data.count)) + } + onReadCallbacks.removeValue(forKey: characteristic) + } + if let onData = onDataCallbacks[characteristic] { + data.withUnsafeBytes { rawBufferPointer -> Void in + let unsafeBufferPointer = rawBufferPointer.bindMemory(to: UInt8.self) + let unsafePointer = unsafeBufferPointer.baseAddress! + let _ = onData(UnsafeRawPointer(board), unsafePointer, UInt8(data.count)) + } + } + if let sources = localReadCallbacks.removeValue(forKey: characteristic) { + sources.forEach { $0.trySet(result: data) } + } + } + public func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { + // didWriteValueFor + } + public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { + logDelegate?.logWith(.info, message: "didUpdateNotificationStateFor \(characteristic)") + subscribeCompleteCallbacks[characteristic]?(UnsafeRawPointer(board), error == nil ? 0 : 1) + } + public func peripheralIsReady(toSendWriteWithoutResponse peripheral: CBPeripheral) { + writeIfNeeded() + } + func writeIfNeeded() { + guard !writeQueue.isEmpty else { + return + } + var canSendWriteWithoutResponse = true + // Starting from iOS 11 and MacOS 10.13 we have a rhobust way to check + // if we can send a message without response and not loose it, so no longer + // need to arbitrary senm every 10th message with response + if #available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *) { + // The peripheral.canSendWriteWithoutResponse often returns false before + // even we start sending, so always send the first + if commandCount != 0 { + guard peripheral.canSendWriteWithoutResponse else { + return + } + } + } else { + // Throttle by having every Nth request wait for response + canSendWriteWithoutResponse = !(commandCount % 10 == 0) + } + commandCount += 1 + let (data, charToWrite, requestedType) = writeQueue.removeFirst() + let type: CBCharacteristicWriteType = canSendWriteWithoutResponse ? requestedType : .withResponse + logDelegate?.logWith(.info, message: "Writing \(type == .withoutResponse ? "NO-RSP" : " RSP"): \(charToWrite.uuid) \(data.hexEncodedString())") + peripheral.writeValue(data, for: charToWrite, type: type) + writeIfNeeded() + } + public func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) { + rssiSources.forEach { $0.trySet(result: RSSI.intValue) } + rssiSources.removeAll() + } +} + + +// Global callback functions +fileprivate func writeGattChar(context: UnsafeMutableRawPointer?, + caller: UnsafeRawPointer?, + writeType: MblMwGattCharWriteType, + characteristicPtr: UnsafePointer?, + valuePtr: UnsafePointer?, + length: UInt8) { + let device: MetaWear = bridge(ptr: context!) + if let charToWrite = device.getCharacteristic(characteristicPtr) { + let data = Data(bytes: valuePtr!, count: Int(length)) + let type: CBCharacteristicWriteType = writeType == MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE ? .withResponse : .withoutResponse + if DispatchQueue.isBleQueue { + device.writeQueue.append((data: data, characteristic: charToWrite, type: type)) + device.writeIfNeeded() + } else { + device.apiAccessQueue.async { + device.writeQueue.append((data: data, characteristic: charToWrite, type: type)) + device.writeIfNeeded() + } + } + } +} + +fileprivate func readGattChar(context: UnsafeMutableRawPointer?, + caller: UnsafeRawPointer?, + characteristicPtr: UnsafePointer?, + callback: MblMwFnIntVoidPtrArray?) { + let device: MetaWear = bridge(ptr: context!) + if let charToRead = device.getCharacteristic(characteristicPtr) { + // Save the callback + device.onReadCallbacks[charToRead] = callback + // Request the read + device.peripheral.readValue(for: charToRead) + } +} + +fileprivate func enableNotifications(context: UnsafeMutableRawPointer?, + caller: UnsafeRawPointer?, + characteristicPtr: UnsafePointer?, + onData: MblMwFnIntVoidPtrArray?, + subscribeComplete: MblMwFnVoidVoidPtrInt?) { + let device: MetaWear = bridge(ptr: context!) + if let charToNotify = device.getCharacteristic(characteristicPtr) { + // Save the callbacks + device.onDataCallbacks[charToNotify] = onData + device.subscribeCompleteCallbacks[charToNotify] = subscribeComplete + // Turn on the notification stream + device.peripheral.setNotifyValue(true, for: charToNotify) + } else { + subscribeComplete?(caller, 1) + } +} + +fileprivate func onDisconnect(context: UnsafeMutableRawPointer?, + caller: UnsafeRawPointer?, + handler: MblMwFnVoidVoidPtrInt?) { + let device: MetaWear = bridge(ptr: context!) + device.onDisconnectCallback = handler +} + +extension Data { + public func hexEncodedString() -> String { + return map { String(format: "%02hhx", $0) }.joined() + } +} diff --git a/Pods/MetaWear/MetaWear/Core/MetaWearData.swift b/Pods/MetaWear/MetaWear/Core/MetaWearData.swift new file mode 100644 index 0000000..652cd60 --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/MetaWearData.swift @@ -0,0 +1,130 @@ +/** + * MetaWearData.swift + * MetaWear-Swift + * + * Created by Stephen Schiffli on 12/14/17. + * Copyright 2017 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + +import MetaWearCpp + + +/// Native swift struct for holding data from the MetaWear +/// This was created because the C++ library destroys MblMwData objects +/// after the callbacks, but sometimes we need them to live longer +public struct MetaWearData { + public let timestamp: Date + let data: [UInt8] + let typeId: MblMwDataTypeId + + public func valueAs() -> T { + return doTheParse(length: UInt8(data.count), type_id: typeId, value: UnsafeRawPointer(data)) + } +} + +extension MblMwData { + public func copy() -> MetaWearData { + let arrayPtr = value.bindMemory(to: UInt8.self, capacity: Int(length)) + return MetaWearData(timestamp: timestamp, + data: Array(UnsafeBufferPointer(start: arrayPtr, count: Int(length))), + typeId: type_id) + } + public var timestamp: Date { + let date = Date(timeIntervalSince1970: Double(epoch) / 1000.0) + let milliseconds = epoch%1000 + return Calendar.current.date(byAdding: .nanosecond, value: Int(milliseconds), to: date)! + } + public func valueAs() -> T { + return doTheParse(length: length, type_id: type_id, value: value) + } + public func extraAs() -> T { + return extra.bindMemory(to: T.self, capacity: 1).pointee + } +} + +fileprivate func doTheParse(length: UInt8, type_id: MblMwDataTypeId, value: UnsafeRawPointer) -> T { + guard type_id != MBL_MW_DT_ID_STRING else { + assert(T.self == String.self || T.self == String?.self) + return String(cString: value.assumingMemoryBound(to: CChar.self)) as! T + } + guard type_id != MBL_MW_DT_ID_BYTE_ARRAY else { + assert(T.self == [UInt8].self) + let buffer = UnsafeRawBufferPointer(start: value, count: Int(length)) + return Array(buffer) as! T + } + guard type_id != MBL_MW_DT_ID_DATA_ARRAY else { + assert(T.self == [MblMwData].self) + let count = Int(length) / MemoryLayout>.size + let pointer = value.bindMemory(to: UnsafePointer.self, capacity: count) + let buffer = UnsafeBufferPointer(start: pointer, count: count) + return buffer.map { $0.pointee } as! T + } + // Generalized flow + assert(MemoryLayout.size == length) + switch type_id { + case MBL_MW_DT_ID_UINT32: + assert(T.self == UInt32.self) + case MBL_MW_DT_ID_FLOAT: + assert(T.self == Float.self) + case MBL_MW_DT_ID_CARTESIAN_FLOAT: + assert(T.self == MblMwCartesianFloat.self) + case MBL_MW_DT_ID_INT32: + assert(T.self == Int32.self) + case MBL_MW_DT_ID_BATTERY_STATE: + assert(T.self == MblMwBatteryState.self) + case MBL_MW_DT_ID_TCS34725_ADC: + assert(T.self == MblMwTcs34725ColorAdc.self) + case MBL_MW_DT_ID_EULER_ANGLE: + assert(T.self == MblMwEulerAngles.self) + case MBL_MW_DT_ID_QUATERNION: + assert(T.self == MblMwQuaternion.self) + case MBL_MW_DT_ID_CORRECTED_CARTESIAN_FLOAT: + assert(T.self == MblMwCorrectedCartesianFloat.self) + case MBL_MW_DT_ID_OVERFLOW_STATE: + assert(T.self == MblMwOverflowState.self) + case MBL_MW_DT_ID_SENSOR_ORIENTATION: + assert(T.self == MblMwSensorOrientation.self) + case MBL_MW_DT_ID_LOGGING_TIME: + assert(T.self == MblMwLoggingTime.self) + case MBL_MW_DT_ID_BTLE_ADDRESS: + assert(T.self == MblMwBtleAddress.self) + case MBL_MW_DT_ID_BOSCH_ANY_MOTION: + assert(T.self == MblMwBoschAnyMotion.self) + case MBL_MW_DT_ID_BOSCH_GESTURE: + assert(T.self == MblMwBoschGestureType.self) + case MBL_MW_DT_ID_CALIBRATION_STATE: + assert(T.self == MblMwCalibrationState.self) + case MBL_MW_DT_ID_BOSCH_TAP: + assert(T.self == MblMwBoschTap.self) + default: + fatalError("unknown data type") + } + return value.bindMemory(to: T.self, capacity: 1).pointee +} diff --git a/Pods/MetaWear/MetaWear/Core/MetaWearScanner.swift b/Pods/MetaWear/MetaWear/Core/MetaWearScanner.swift new file mode 100644 index 0000000..6ac84f6 --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/MetaWearScanner.swift @@ -0,0 +1,270 @@ +/** + * MetaWearScanner.swift + * MetaWear-Swift + * + * Created by Stephen Schiffli on 12/14/17. + * Copyright 2017 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + +import CoreBluetooth +import BoltsSwift + + +fileprivate let rememberedDevicesKey = "com.mbientlab.rememberedDevices" +fileprivate var scannerCount = 0 + +/// Scanner utility, make is simple to start scanning for MetaWear devices without +/// having to understand all of CoreBluetooth +public class MetaWearScanner: NSObject { + public static let shared = MetaWearScanner() + public static let sharedRestore = MetaWearScanner(restoreIdentifier: "MetaWearScanner.shared") + public var central: CBCentralManager! = nil + /// All devices that have been discovered in one way or another by this central + public var deviceMap: [CBPeripheral: MetaWear] = [:] + public var didUpdateState: ((CBCentralManager) -> Void)? { + didSet { + didUpdateState?(central) + } + } + + public init(restoreIdentifier: String? = nil) { + super.init() + let options: [String : Any] = restoreIdentifier == nil ? [:] : [CBCentralManagerOptionRestoreIdentifierKey: restoreIdentifier!] + self.central = CBCentralManager(delegate: self, + queue: bleQueue, + options: options) + } + + /// Start the scaning process for MetaWear or MetaBoot devices + public func startScan(allowDuplicates: Bool, callback: @escaping (MetaWear) -> Void) { + runWhenPoweredOn { + self.callback = callback + self.central.scanForPeripherals(withServices: [.metaWearService, + .metaWearDfuService], + options: [CBCentralManagerScanOptionAllowDuplicatesKey: allowDuplicates]) + // Restart scanning if BLE state toggles off then on + self.runOnPowerOff.append { [unowned self] in + if let callback = self.callback { + self.startScan(allowDuplicates: allowDuplicates, callback: callback) + } + } + } + } + + /// Stop scanning + public func stopScan() { + self.callback = nil + runWhenPoweredOn { + self.central.stopScan() + } + } + + /// List of devices stored via `MetaWear.remember()` + public func retrieveSavedMetaWearsAsync() -> Task<[MetaWear]> { + let source = TaskCompletionSource<[MetaWear]>() + runWhenPoweredOn { + var devices: [MetaWear] = [] + if let ids = UserDefaults.standard.stringArray(forKey: rememberedDevicesKey) { + let uuids = ids.map { UUID(uuidString: $0)! } + let peripherals = self.central.retrievePeripherals(withIdentifiers: uuids) + devices = peripherals.map { peripheral -> MetaWear in + let device = self.deviceMap[peripheral] ?? MetaWear(peripheral: peripheral, scanner: self) + self.deviceMap[peripheral] = device + return device + } + } + source.trySet(result: devices) + } + return source.task + } + + /// List of devices that are already connected + /// This is useful to check after state was restored + public func retrieveConnectedMetaWearsAsync() -> Task<[MetaWear]> { + let source = TaskCompletionSource<[MetaWear]>() + runWhenPoweredOn { + var devices: [MetaWear] = [] + let peripherals = self.central.retrieveConnectedPeripherals(withServices: [.metaWearService, + .metaWearDfuService]) + devices = peripherals.map { peripheral -> MetaWear in + let device = self.deviceMap[peripheral] ?? MetaWear(peripheral: peripheral, scanner: self) + self.deviceMap[peripheral] = device + return device + } + source.trySet(result: devices) + } + return source.task + } + + // Internal details below + var allowDuplicates: Bool = false + var callback: ((MetaWear) -> Void)? + var isScanning = false + var centralStateUpdateSources: [TaskCompletionSource<()>] = [] + var runOnPowerOn: [() -> Void] = [] + var runOnPowerOff: [() -> Void] = [] + public let bleQueue: DispatchQueue = { + let queue = DispatchQueue(label: "com.mbientlab.bleQueue\(scannerCount)") + scannerCount += 1 + queue.setSpecific(key: bleQueueKey, value: bleQueueValue) + return queue + }() + + func connect(_ device: MetaWear) { + runWhenPoweredOn { + self.central.connect(device.peripheral) + } + } + + func cancelConnection(_ device: MetaWear) { + runWhenPoweredOn { + self.central.cancelPeripheralConnection(device.peripheral) + } + } + + func runWhenPoweredOn(_ code: @escaping () -> Void) { + bleQueue.async { + if self.central.state == .poweredOn { + code() + } else { + self.runOnPowerOn.append(code) + } + } + } + + func remember(_ device: MetaWear) { + let idString = device.peripheral.identifier.uuidString + var devices = UserDefaults.standard.stringArray(forKey: rememberedDevicesKey) ?? [] + if !devices.contains(idString) { + devices.append(idString) + } + UserDefaults.standard.set(devices, forKey: rememberedDevicesKey) + } + func forget(_ device: MetaWear) { + var devices = UserDefaults.standard.stringArray(forKey: rememberedDevicesKey) + if let idx = devices?.firstIndex(of: device.peripheral.identifier.uuidString) { + devices?.remove(at: idx) + UserDefaults.standard.set(devices, forKey: rememberedDevicesKey) + } + } + + func updateCentralStateSource(_ source: TaskCompletionSource<()>) { + switch central.state { + case .unknown: + break // Updates are imminent, so wait + case .resetting: + break // Updates are imminent, so wait + case .unsupported: + source.set(error: MetaWearError.bluetoothUnsupported) + case .unauthorized: + source.set(error: MetaWearError.bluetoothUnauthorized) + case .poweredOff: + source.set(error: MetaWearError.bluetoothPoweredOff) + case .poweredOn: + source.set(result: ()) + @unknown default: + fatalError("new central.state values, please update.") + } + } + + func centralStateTask() -> Task<()> { + let source = TaskCompletionSource<()>() + bleQueue.async { + self.updateCentralStateSource(source) + if !source.task.completed { + self.centralStateUpdateSources.append(source) + } + } + return source.task + } +} + +fileprivate let bleQueueKey = DispatchSpecificKey() +fileprivate let bleQueueValue = 1111 +extension DispatchQueue { + class var isBleQueue: Bool { + return DispatchQueue.getSpecific(key: bleQueueKey) == bleQueueValue + } +} + +extension MetaWearScanner: CBCentralManagerDelegate { + public func centralManagerDidUpdateState(_ central: CBCentralManager) { + didUpdateState?(central) + + // TODO: This seems like an iOS bug. If bluetooth powers off the + // peripherials disconnect, but we don't get a deviceDidDisconnect callback. + if central.state != .poweredOn { + deviceMap.forEach { $0.value.didDisconnectPeripheral(error: MetaWearError.bluetoothPoweredOff) } + } + // Execute all commands when the central is ready + if central.state == .poweredOn { + let localRunOnPowerOn = runOnPowerOn + runOnPowerOn.removeAll() + localRunOnPowerOn.forEach { $0() } + } else if central.state == .poweredOff { + let localRunOnPowerOff = runOnPowerOff + runOnPowerOff.removeAll() + localRunOnPowerOff.forEach { $0() } + } + + centralStateUpdateSources.forEach { self.updateCentralStateSource($0) } + centralStateUpdateSources = centralStateUpdateSources.filter { !$0.task.completed } + } + public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { + let device = deviceMap[peripheral] ?? MetaWear(peripheral: peripheral, scanner: self) + deviceMap[peripheral] = device + device.didDiscover(advertisementData: advertisementData, rssi: RSSI) + callback?(device) + } + public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { + deviceMap[peripheral]?.didConnect() + } + public func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { + deviceMap[peripheral]?.didFailToConnect(error: error) + } + public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { + deviceMap[peripheral]?.didDisconnectPeripheral(error: error) + } + public func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) { + // As an SDK, we arn't sure what operations the user is acutally doing. + // You should place code in didFinishLaunchingWithOptions to kick off any tasks + // you expect to take place + + // An array (an instance of NSArray) of CBPeripheral objects that contains + // all of the peripherals that were connected to the central manager + // (or had a connection pending) at the time the app was terminated by the system. + if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey] as? [CBPeripheral] { + for peripheral in peripherals { + let device = MetaWear(peripheral: peripheral, scanner: self) + self.deviceMap[peripheral] = device + } + } + } +} diff --git a/Pods/MetaWear/MetaWear/Core/String+VersionCompare.swift b/Pods/MetaWear/MetaWear/Core/String+VersionCompare.swift new file mode 100644 index 0000000..389ce88 --- /dev/null +++ b/Pods/MetaWear/MetaWear/Core/String+VersionCompare.swift @@ -0,0 +1,67 @@ +/** + * String+VersionCompare.swift + * MetaWear-Swift + * + * Created by Stephen Schiffli on 1/22/18. + * Copyright 2018 MbientLab Inc. All rights reserved. + * + * IMPORTANT: Your use of this Software is limited to those specific rights + * granted under the terms of a software license agreement between the user who + * downloaded the software, his/her employer (which must be your employer) and + * MbientLab Inc, (the "License"). You may not use this Software unless you + * agree to abide by the terms of the License which can be found at + * www.mbientlab.com/terms. The License limits your use, and you acknowledge, + * that the Software may be modified, copied, and distributed when used in + * conjunction with an MbientLab Inc, product. Other than for the foregoing + * purpose, you may not use, reproduce, copy, prepare derivative works of, + * modify, distribute, perform, display or sell this Software and/or its + * documentation for any purpose. + * + * YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE + * PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, + * NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL + * MBIENTLAB OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, + * STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE + * THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED + * TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST + * PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, + * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY + * DEFENSE THEREOF), OR OTHER SIMILAR COSTS. + * + * Should you have any questions regarding your right to use this Software, + * contact MbientLab via email: hello@mbientlab.com + */ + + +/// String helper functions +extension String { + /// Inner comparison utility to handle same versions with different length. (Ex: "1.0.0" & "1.0") + private func compare(toVersion targetVersion: String) -> ComparisonResult { + let versionDelimiter = "." + var result: ComparisonResult = .orderedSame + var versionComponents = components(separatedBy: versionDelimiter) + var targetComponents = targetVersion.components(separatedBy: versionDelimiter) + let spareCount = versionComponents.count - targetComponents.count + + if spareCount == 0 { + result = compare(targetVersion, options: .numeric) + } else { + let spareZeros = repeatElement("0", count: abs(spareCount)) + if spareCount > 0 { + targetComponents.append(contentsOf: spareZeros) + } else { + versionComponents.append(contentsOf: spareZeros) + } + result = versionComponents.joined(separator: versionDelimiter) + .compare(targetComponents.joined(separator: versionDelimiter), options: .numeric) + } + return result + } + + public func isVersion(equalTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedSame } + public func isVersion(greaterThan targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedDescending } + public func isVersion(greaterThanOrEqualTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) != .orderedAscending } + public func isVersion(lessThan targetVersion: String) -> Bool { return compare(toVersion: targetVersion) == .orderedAscending } + public func isVersion(lessThanOrEqualTo targetVersion: String) -> Bool { return compare(toVersion: targetVersion) != .orderedDescending } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/bindings/swift/cbindings.swift b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/bindings/swift/cbindings.swift new file mode 100644 index 0000000..5cf5db8 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/bindings/swift/cbindings.swift @@ -0,0 +1,44 @@ +public let MBL_MW_MODULE_BARO_TYPE_BME280 = 1 +public let MBL_MW_MODULE_BARO_TYPE_BMP280 = 0 +public let MBL_MW_GYRO_ROTATION_Z_AXIS_INDEX = 2 +public let MBL_MW_GYRO_ROTATION_Y_AXIS_INDEX = 1 +public let MBL_MW_GYRO_ROTATION_X_AXIS_INDEX = 0 +public let MBL_MW_MODULE_ACC_TYPE_BMI270 = 4 +public let MBL_MW_SETTINGS_POWER_STATUS_UNSUPPORTED = -1 +public let MBL_MW_STATUS_OK = 0 +public let MBL_MW_ADDRESS_TYPE_PRIVATE_NON_RESOLVABLE = 3 +public let MBL_MW_MODULE_GYRO_TYPE_BMI160 = 0 +public let MBL_MW_CD_TCS34725_ADC_BLUE_INDEX = 3 +public let MBL_MW_STATUS_ERROR_ENABLE_NOTIFY = 64 +public let MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE = 2 +public let MBL_MW_SETTINGS_CHARGE_STATUS_UNSUPPORTED = -1 +public let MBL_MW_SETTINGS_BATTERY_CHARGE_INDEX = 1 +public let MBL_MW_SETTINGS_BATTERY_VOLTAGE_INDEX = 0 +public let MBL_MW_MODULE_GYRO_TYPE_BMI270 = 1 +public let MBL_MW_CD_TCS34725_ADC_CLEAR_INDEX = 0 +public let MBL_MW_STATUS_ERROR_TIMEOUT = 16 +public let MBL_MW_ADDRESS_TYPE_PRIVATE_RESOLVABLE = 2 +public let MBL_MW_CD_TCS34725_ADC_RED_INDEX = 1 +public let MBL_MW_MODULE_TYPE_NA = -1 +public let MBL_MW_STATUS_ERROR_SERIALIZATION_FORMAT = 32 +public let MBL_MW_ACC_ACCEL_Y_AXIS_INDEX = 1 +public let MBL_MW_STATUS_WARNING_UNEXPECTED_SENSOR_DATA = 1 +public let MBL_MW_CD_TCS34725_ADC_GREEN_INDEX = 2 +public let MBL_MW_ADDRESS_TYPE_RANDOM_STATIC = 1 +public let MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR = 4 +public let MBL_MW_ADDRESS_TYPE_PUBLIC = 0 +public let MBL_MW_STATUS_WARNING_INVALID_RESPONSE = 8 +public let MBL_MW_SENSOR_FUSION_CALIBRATION_ACCURACY_MEDIUM = 2 +public let MBL_MW_LED_REPEAT_INDEFINITELY = 255 +public let MBL_MW_MAG_BFIELD_Z_AXIS_INDEX = 2 +public let MBL_MW_MODULE_ACC_TYPE_BMA255 = 3 +public let MBL_MW_SENSOR_FUSION_CALIBRATION_ACCURACY_UNRELIABLE = 0 +public let MBL_MW_SENSOR_FUSION_CALIBRATION_ACCURACY_HIGH = 3 +public let MBL_MW_MAG_BFIELD_X_AXIS_INDEX = 0 +public let MBL_MW_MAG_BFIELD_Y_AXIS_INDEX = 1 +public let MBL_MW_SENSOR_FUSION_CALIBRATION_ACCURACY_LOW = 1 +public let MBL_MW_ACC_ACCEL_Z_AXIS_INDEX = 2 +public let MBL_MW_ACC_ACCEL_X_AXIS_INDEX = 0 +public let MBL_MW_GPIO_UNUSED_PIN = 255 +public let MBL_MW_MODULE_ACC_TYPE_MMA8452Q = 0 +public let MBL_MW_MODULE_ACC_TYPE_BMI160 = 1 diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/anonymous_datasignal.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/anonymous_datasignal.h new file mode 100644 index 0000000..0bfa462 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/anonymous_datasignal.h @@ -0,0 +1,32 @@ +/** + * @copyright MbientLab License + * @file anonymous_datasignal.h + * @brief Functions operating on the MblMwAnonymousDataSignal object + */ +#pragma once + +#include "metawear/platform/dllmarker.h" + +#include "anonymous_datasignal_fwd.h" +#include "data.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Subscribe to the data produced by the signal + * @param signal Calling object + * @param context Pointer to additional data for the callback function + * @param data_handler Callback function to handle data received from the signal + */ +METAWEAR_API void mbl_mw_anonymous_datasignal_subscribe(MblMwAnonymousDataSignal* signal, void *context, MblMwFnData data_handler); +/** + * Generates a string identifying the data chain the anonymous data signal is receiving data from. + * @return String identifying the data chain + */ +METAWEAR_API const char* mbl_mw_anonymous_datasignal_get_identifier(const MblMwAnonymousDataSignal* signal); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/anonymous_datasignal_fwd.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/anonymous_datasignal_fwd.h new file mode 100644 index 0000000..6c536cb --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/anonymous_datasignal_fwd.h @@ -0,0 +1,27 @@ +/** + * @copyright MbientLab License + * @file anonymous_datasignal_fwd.h + * @brief Forward declaration for the MblMwAnonymousDataSignal type + */ +#pragma once + +#include "metawearboard_fwd.h" + +/** + * A variant of an MblMwDataLogger object, used to retrieve logged data from a board + * that was not programmed by the current host device + */ +#ifdef __cplusplus +struct MblMwAnonymousDataSignal; +#else +typedef struct MblMwAnonymousDataSignal MblMwAnonymousDataSignal; +#endif + +/** + * Definition for callback functions that accept an MblMwMetaWearBoard pointer, MblMwAnonymousDataSignal double pointers, and an uint32 value + * @param context Pointer to the context the enclosing function was called with + * @param board Board pointer to be used with the function + * @param anonymous_signals Array of MblMwAnonymousDataSignal pointers + * @param size Number of elements in the array + */ +typedef void(*MblMwFnAnonSignalArray)(void *context, MblMwMetaWearBoard* board, MblMwAnonymousDataSignal** anonymous_signals, uint32_t size); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal.cpp new file mode 100644 index 0000000..65c0850 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal.cpp @@ -0,0 +1,12 @@ +#include "anonymous_datasignal_private.h" +#include "metawear/core/anonymous_datasignal.h" + +MblMwAnonymousDataSignal::~MblMwAnonymousDataSignal() { } + +void mbl_mw_anonymous_datasignal_subscribe(MblMwAnonymousDataSignal* signal, void *context, MblMwFnData data_handler) { + signal->subscribe(context, data_handler); +} + +const char* mbl_mw_anonymous_datasignal_get_identifier(const MblMwAnonymousDataSignal* signal) { + return signal->get_identifier(); +} \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal_private.h new file mode 100644 index 0000000..2c82a07 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal_private.h @@ -0,0 +1,11 @@ +#pragma once + +#include "metawear/core/anonymous_datasignal_fwd.h" +#include "metawear/core/data.h" + +struct MblMwAnonymousDataSignal { + virtual ~MblMwAnonymousDataSignal() = 0; + + virtual void subscribe(void *context, MblMwFnData data_handler) = 0; + virtual const char* get_identifier() const = 0; +}; \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/constant.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/constant.h new file mode 100644 index 0000000..5c574a0 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/constant.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +const uint8_t MW_CMD_MAX_LENGTH= 18, BLE_PACKET_SIZE = MW_CMD_MAX_LENGTH + 2; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datainterpreter.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datainterpreter.h new file mode 100644 index 0000000..cc0ec3d --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datainterpreter.h @@ -0,0 +1,80 @@ +#pragma once + +#include + +#include "metawear/core/data.h" +#include "metawear/core/datasignal_fwd.h" + +enum class DataInterpreter : uint8_t { + INT32, + UINT32, + TEMPERATURE, + BOSCH_PRESSURE, + BOSCH_ALTITUDE, + BOSCH_ROTATION, + BOSCH_ROTATION_SINGLE_AXIS, + BOSCH_ACCELERATION, + BOSCH_ACCELERATION_SINGLE_AXIS, + MMA8452Q_ACCELERATION, + MMA8452Q_ACCELERATION_SINGLE_AXIS, + BYTE_ARRAY, + BMM150_B_FIELD, + BMM150_B_FIELD_SINGLE_AXIS, + SETTINGS_BATTERY_STATE, + TCS34725_COLOR_ADC, + BME280_HUMIDITY, + Q16_16_FIXED_POINT, + BOSCH_ROTATION_UNSIGNED_SINGLE_AXIS, + BOSCH_ACCELERATION_UNSIGNED_SINGLE_AXIS, + MMA8452Q_ACCELERATION_UNSIGNED_SINGLE_AXIS, + BMM150_B_FIELD_UNSIGNED_SINGLE_AXIS, + SENSOR_FUSION_QUATERNION, + SENSOR_FUSION_EULER_ANGLE, + SENSOR_FUSION_CORRECTED_FLOAT_VECTOR3, + SENSOR_FUSION_FLOAT_VECTOR3, + SENSOR_FUSION_CORRECTED_ACC, + DEBUG_OVERFLOW_STATE, + SENSOR_ORIENTATION, + MAC_ADDRESS, + SENSOR_ORIENTATION_MMA8452Q, + LOGGING_TIME, + BTLE_ADDRESS, + BOSCH_ANY_MOTION, + SENSOR_FUSION_CALIB_STATE, + FUSED_DATA, + BOSCH_TAP, + BMI270_GESTURE, + BMI270_ACTIVITY +}; + +enum class FirmwareConverter : uint8_t { + DEFAULT, + BME280_HUMIDITY, + BOSCH_ACCELERATION, + BOSCH_BAROMETER, + BOSCH_ROTATION, + MMA8452Q_ACCELERATION, + TEMPERATURE, + Q16_16_FIXED_POINT, + BOSCH_MAGNETOMETER +}; + +namespace std { + template <> + struct hash { + size_t operator()(const DataInterpreter& key) const; + }; + + template <> + struct hash { + size_t operator()(const FirmwareConverter& key) const; + }; +} + +typedef MblMwData* (*FnBoolDataSignalByteArray)(bool log_data, const MblMwDataSignal*, const uint8_t*, uint8_t); +extern std::unordered_map data_response_converters; + +typedef float (*FnDataSignalFloat)(const MblMwDataSignal*, float); +extern std::unordered_map number_to_firmware_converters; + +void free_data(const MblMwDataSignal* signal, MblMwData* data); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal.cpp new file mode 100644 index 0000000..fc97b32 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal.cpp @@ -0,0 +1,254 @@ +#include "metawear/core/datasignal.h" + +#include "datainterpreter.h" +#include "datasignal_private.h" +#include "metawearboard_def.h" + +#include "settings_private.h" +#include "metawear/sensor/cpp/accelerometer_private.h" +#include "metawear/sensor/cpp/ambientlight_ltr329_private.h" +#include "metawear/sensor/cpp/barometer_bosch_private.h" +#include "metawear/sensor/cpp/colordetector_tcs34725_private.h" +#include "metawear/sensor/cpp/gpio_private.h" +#include "metawear/sensor/cpp/gyro_bosch_private.h" +#include "metawear/sensor/cpp/humidity_bme280_private.h" +#include "metawear/sensor/cpp/magnetometer_bmm150_private.h" +#include "metawear/sensor/cpp/multichanneltemperature_private.h" +#include "metawear/sensor/cpp/proximity_tsl2671_private.h" +#include "metawear/sensor/cpp/sensor_fusion_private.h" +#include "metawear/sensor/cpp/serialpassthrough_private.h" +#include "metawear/sensor/cpp/switch_private.h" + +#include + +using std::out_of_range; +using std::stringstream; +using std::vector; + +uint8_t MblMwDataSignal::count_subscribers(const MblMwDataSignal* signal) { + auto root= dynamic_cast(signal->owner->module_events.at(signal->header)); + uint8_t count= root->handler == nullptr ? 0 : 1; + + for(auto it: root->components) { + if (it->handler != nullptr) { + count++; + } + } + return count; +} + +MblMwDataSignal::MblMwDataSignal(uint8_t** state_stream, MblMwMetaWearBoard *owner) : MblMwEvent(state_stream, owner), handler(nullptr) { + interpreter = static_cast(**state_stream); + converter = static_cast(*(++(*state_stream))); + n_channels = *(++(*state_stream)); + channel_size = *(++(*state_stream)); + is_signed = *(++(*state_stream)); + offset = *(++(*state_stream)); + + (*state_stream)++; +} + +MblMwDataSignal::MblMwDataSignal(const MblMwEvent& event) : MblMwDataSignal(event.header, event.owner, DataInterpreter::UINT32, 0, 0, 0, 0) { +} + +MblMwDataSignal::MblMwDataSignal(const ResponseHeader& header, MblMwMetaWearBoard *owner, DataInterpreter interpreter, FirmwareConverter converter, + uint8_t n_channels, uint8_t channel_size, uint8_t is_signed, uint8_t offset) : + MblMwEvent(header, owner), handler(nullptr), interpreter(interpreter), converter(converter), n_channels(n_channels), + channel_size(channel_size), is_signed(is_signed), offset(offset) { + // Initialize readable signals to silent reads + if (this->header.is_readable()) { + this->header.enable_silent(); + } +} + +MblMwDataSignal::MblMwDataSignal(const ResponseHeader& header, MblMwMetaWearBoard *owner, DataInterpreter interpreter, + uint8_t n_channels, uint8_t channel_size, uint8_t is_signed, uint8_t offset) : + MblMwDataSignal(header, owner, interpreter, FirmwareConverter::DEFAULT, n_channels, channel_size, is_signed, offset) { +} + +MblMwDataSignal::~MblMwDataSignal() { + for(auto it: components) { + delete it; + } +} + +void MblMwDataSignal::subscribe() { + if (this->header.is_readable()) { + this->header.disable_silent(); + } else { + if (count_subscribers(this) == 1) { + uint8_t command[3] = { header.module_id, header.register_id, 1 }; + SEND_COMMAND_BOARD(owner); + } + } +} + +void MblMwDataSignal::unsubscribe() { + if (this->header.is_readable()) { + this->header.enable_silent(); + } else { + if (!count_subscribers(this)) { + uint8_t command[3] = { header.module_id, header.register_id, 0 }; + SEND_COMMAND_BOARD(owner); + } + } +} + +void MblMwDataSignal::read() const { + if (header.has_data_id()) { + uint8_t command[2]= { header.module_id, header.register_id }; + SEND_COMMAND_BOARD(owner); + } else { + uint8_t command[3]= { header.module_id, header.register_id, header.data_id }; + SEND_COMMAND_BOARD(owner); + } +} + +void MblMwDataSignal::read(const void* parameters) const { + read(); +} + +void MblMwDataSignal::serialize(vector& state) const { + MblMwEvent::serialize(state); + + state.push_back(static_cast(interpreter)); + state.push_back(static_cast(converter)); + state.push_back(n_channels); + state.push_back(channel_size); + state.push_back(is_signed); + state.push_back(offset); +} + +void MblMwDataSignal::create_uri(stringstream& uri) const { + switch(header.module_id) { + case MBL_MW_MODULE_SWITCH: + return create_switch_uri(this, uri); + case MBL_MW_MODULE_ACCELEROMETER: + return create_acc_uri(this, uri); + case MBL_MW_MODULE_TEMPERATURE: + return create_temp_uri(this, uri); + case MBL_MW_MODULE_GPIO: + return create_gpio_uri(this, uri); + case MBL_MW_MODULE_DATA_PROCESSOR: + return create_dataprocessor_state_uri(this, uri); + case MBL_MW_MODULE_I2C: + return create_serialpassthrough_uri(this, uri); + case MBL_MW_MODULE_SETTINGS: + return create_settings_uri(this, uri); + case MBL_MW_MODULE_BAROMETER: + return create_barometer_uri(this, uri); + case MBL_MW_MODULE_GYRO: + return create_gyro_uri(this, uri); + case MBL_MW_MODULE_AMBIENT_LIGHT: + return create_als_uri(this, uri); + case MBL_MW_MODULE_MAGNETOMETER: + return create_magnetometer_uri(this, uri); + case MBL_MW_MODULE_HUMIDITY: + return create_humidity_uri(this, uri); + case MBL_MW_MODULE_COLOR_DETECTOR: + return create_colordetector_uri(this, uri); + case MBL_MW_MODULE_PROXIMITY: + return create_proximity_uri(this, uri); + case MBL_MW_MODULE_SENSOR_FUSION: + return create_sensor_fusion_uri(this, uri); + } +} + +uint8_t MblMwDataSignal::length() const { + return n_channels * channel_size; +} + +uint8_t MblMwDataSignal::get_data_ubyte() const { + return ((length() - 1) << 5) | offset; +} + +void MblMwDataSignal::set_channel_attr(uint8_t n_channels, uint8_t channel_size) { + this->n_channels= n_channels; + this->channel_size= channel_size; +} + +void MblMwDataSignal::make_signed() { + is_signed= 1; + + switch (interpreter) { + case DataInterpreter::UINT32: + interpreter = DataInterpreter::INT32; + break; + case DataInterpreter::BOSCH_ROTATION_UNSIGNED_SINGLE_AXIS: + interpreter = DataInterpreter::BOSCH_ROTATION_SINGLE_AXIS; + break; + case DataInterpreter::BOSCH_ACCELERATION_UNSIGNED_SINGLE_AXIS: + interpreter = DataInterpreter::BOSCH_ACCELERATION_SINGLE_AXIS; + break; + case DataInterpreter::MMA8452Q_ACCELERATION_UNSIGNED_SINGLE_AXIS: + interpreter = DataInterpreter::MMA8452Q_ACCELERATION_SINGLE_AXIS; + break; + case DataInterpreter::BMM150_B_FIELD_UNSIGNED_SINGLE_AXIS: + interpreter = DataInterpreter::BMM150_B_FIELD_SINGLE_AXIS; + break; + case DataInterpreter::BOSCH_PRESSURE: + interpreter = DataInterpreter::BOSCH_ALTITUDE; + break; + default: + break; + } +} + +void MblMwDataSignal::make_unsigned() { + is_signed= 0; + + switch (interpreter) { + case DataInterpreter::INT32: + interpreter = DataInterpreter::UINT32; + break; + case DataInterpreter::BOSCH_ROTATION_SINGLE_AXIS: + interpreter = DataInterpreter::BOSCH_ROTATION_UNSIGNED_SINGLE_AXIS; + break; + case DataInterpreter::BOSCH_ACCELERATION_SINGLE_AXIS: + interpreter = DataInterpreter::BOSCH_ACCELERATION_UNSIGNED_SINGLE_AXIS; + break; + case DataInterpreter::MMA8452Q_ACCELERATION_SINGLE_AXIS: + interpreter = DataInterpreter::MMA8452Q_ACCELERATION_UNSIGNED_SINGLE_AXIS; + break; + case DataInterpreter::BMM150_B_FIELD_SINGLE_AXIS: + interpreter = DataInterpreter::BMM150_B_FIELD_UNSIGNED_SINGLE_AXIS; + break; + case DataInterpreter::BOSCH_ALTITUDE: + interpreter = DataInterpreter::BOSCH_PRESSURE; + break; + default: + break; + } +} + +MblMwDataSignal* mbl_mw_datasignal_get_component(const MblMwDataSignal* signal, uint8_t index) { + try { + return signal->components.at(index); + } catch (const out_of_range&) { + return nullptr; + } +} + +void mbl_mw_datasignal_subscribe(MblMwDataSignal *signal, void *context, MblMwFnData received_data) { + signal->context= context; + signal->handler= received_data; + signal->subscribe(); +} + +void mbl_mw_datasignal_unsubscribe(MblMwDataSignal *signal) { + signal->context= nullptr; + signal->handler= nullptr; + signal->unsubscribe(); +} + +void mbl_mw_datasignal_read(const MblMwDataSignal* signal) { + signal->read(); +} + +void mbl_mw_datasignal_read_with_parameters(const MblMwDataSignal* signal, const void* parameters) { + signal->read(parameters); +} + +int32_t mbl_mw_datasignal_is_readable(const MblMwDataSignal* signal) { + return signal->header.is_readable(); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal_private.h new file mode 100644 index 0000000..394032b --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal_private.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include "metawear/core/datasignal_fwd.h" +#include "metawear/core/data.h" +#include "datainterpreter.h" +#include "event_private.h" + +struct MblMwDataSignal : public MblMwEvent { + static uint8_t count_subscribers(const MblMwDataSignal* signal); + + MblMwDataSignal(uint8_t** state_stream, MblMwMetaWearBoard *owner); + MblMwDataSignal(const MblMwEvent& event); + MblMwDataSignal(const ResponseHeader& header, MblMwMetaWearBoard *owner, DataInterpreter interpreter, uint8_t n_channels, + uint8_t channel_size, uint8_t is_signed, uint8_t offset); + MblMwDataSignal(const ResponseHeader& header, MblMwMetaWearBoard *owner, DataInterpreter interpreter, FirmwareConverter converter, + uint8_t n_channels, uint8_t channel_size, uint8_t is_signed, uint8_t offset); + virtual ~MblMwDataSignal(); + + virtual void read() const; + virtual void read(const void* parameters) const; + virtual void subscribe(); + virtual void unsubscribe(); + virtual void serialize(std::vector& state) const; + + virtual void create_uri(std::stringstream& uri) const; + + uint8_t length() const; + uint8_t get_data_ubyte() const; + + void set_channel_attr(uint8_t n_channels, uint8_t channel_size); + void make_signed(); + void make_unsigned(); + + void *context; + MblMwFnData handler; + std::vector components; + + DataInterpreter interpreter; + FirmwareConverter converter; + uint8_t n_channels; + uint8_t channel_size; + uint8_t is_signed; + uint8_t offset; +}; + +void create_dataprocessor_state_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug.cpp new file mode 100644 index 0000000..3bbcc25 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug.cpp @@ -0,0 +1,155 @@ +#include "metawearboard_def.h" +#include "datainterpreter.h" +#include "debug_private.h" +#include "register.h" +#include "datasignal_private.h" + +#include "metawear/core/debug.h" +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/core/cpp/metawearboard_macro.h" + +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +enum class DebugRegister : uint8_t { + RESET = 0x1, + BOOTLOADER, + NOTIFICATION_SPOOF, + KEY_REGISTER, + RESET_GC, + DISCONNECT, + POWER_SAVE, + STACK_OVERFLOW = 0x9, + SCHEDULE_QUEUE +}; + +struct DebugState { + MblMwFnData overflow_state_handler, schedule_queue_handler; + void *overflow_state_context; + void *schedule_queue_context; +}; + +const uint8_t RES_MONITOR_REVISION= 2; + +const ResponseHeader + DEBUG_KEY_REGISTER_RESPONSE_HEADER(MBL_MW_MODULE_DEBUG, READ_REGISTER(ORDINAL(DebugRegister::KEY_REGISTER))); + +#define GET_DEBUG_STATE(board) static_pointer_cast(board->debug_state) +#define CAST_RESPONSE(type, context, handler) auto data = data_response_converters.at(type)(false, nullptr, response + 2, len - 2);\ +data->epoch = duration_cast(system_clock::now().time_since_epoch()).count();\ +\ +GET_DEBUG_STATE(board)->handler(GET_DEBUG_STATE(board)->context, data);\ +free_data(nullptr, data) + +static int32_t schedule_queue_status_received(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + CAST_RESPONSE(DataInterpreter::BYTE_ARRAY, schedule_queue_context, schedule_queue_handler); + return MBL_MW_STATUS_OK; +} + +static int32_t overflow_status_received(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + CAST_RESPONSE(DataInterpreter::DEBUG_OVERFLOW_STATE, overflow_state_context, overflow_state_handler); + return MBL_MW_STATUS_OK; +} + +void init_debug_module(MblMwMetaWearBoard *board) { + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_DEBUG, READ_REGISTER(ORDINAL(DebugRegister::SCHEDULE_QUEUE))), + forward_as_tuple(schedule_queue_status_received)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_DEBUG, READ_REGISTER(ORDINAL(DebugRegister::STACK_OVERFLOW))), + forward_as_tuple(overflow_status_received)); + + if (!board->module_events.count(DEBUG_KEY_REGISTER_RESPONSE_HEADER)) { + board->module_events[DEBUG_KEY_REGISTER_RESPONSE_HEADER] = new MblMwDataSignal(DEBUG_KEY_REGISTER_RESPONSE_HEADER, board, + DataInterpreter::UINT32, 1, 4, 0, 0); + } + board->responses[DEBUG_KEY_REGISTER_RESPONSE_HEADER] = response_handler_data_no_id; + + if (!board->debug_state) { + board->debug_state = make_shared(); + } +} + +void free_debug_module(void *state) { + delete (DebugState*) state; +} + +void mbl_mw_debug_reset(const MblMwMetaWearBoard *board) { + uint8_t command[2]= {MBL_MW_MODULE_DEBUG, ORDINAL(DebugRegister::RESET)}; + SEND_COMMAND; +} + +void mbl_mw_debug_jump_to_bootloader(const MblMwMetaWearBoard *board) { + uint8_t command[2]= {MBL_MW_MODULE_DEBUG, ORDINAL(DebugRegister::BOOTLOADER)}; + SEND_COMMAND; +} + +void mbl_mw_debug_disconnect(const MblMwMetaWearBoard *board) { + uint8_t command[2]= {MBL_MW_MODULE_DEBUG, ORDINAL(DebugRegister::DISCONNECT)}; + SEND_COMMAND; +} + +void mbl_mw_debug_reset_after_gc(const MblMwMetaWearBoard *board) { + uint8_t command[2]= {MBL_MW_MODULE_DEBUG, ORDINAL(DebugRegister::RESET_GC)}; + SEND_COMMAND; +} + +void mbl_mw_debug_enable_power_save(const MblMwMetaWearBoard *board) { + uint8_t command[2]= {MBL_MW_MODULE_DEBUG, ORDINAL(DebugRegister::POWER_SAVE)}; + SEND_COMMAND; +} + +void mbl_mw_debug_read_schedule_queue_usage(const MblMwMetaWearBoard *board, void *context, MblMwFnData handler) { + if (board->module_info.at(MBL_MW_MODULE_DEBUG).revision >= RES_MONITOR_REVISION) { + GET_DEBUG_STATE(board)->schedule_queue_context = context; + GET_DEBUG_STATE(board)->schedule_queue_handler = handler; + + uint8_t command[2]= {MBL_MW_MODULE_DEBUG, READ_REGISTER(ORDINAL(DebugRegister::SCHEDULE_QUEUE))}; + SEND_COMMAND; + } else { + handler(context, nullptr); + } +} + +void mbl_mw_debug_set_stack_overflow_assertion(const MblMwMetaWearBoard *board, uint8_t enable) { + if (board->module_info.at(MBL_MW_MODULE_DEBUG).revision >= RES_MONITOR_REVISION) { + uint8_t command[3]= {MBL_MW_MODULE_DEBUG, ORDINAL(DebugRegister::STACK_OVERFLOW), static_cast(enable == 0 ? enable : 1)}; + SEND_COMMAND; + } +} + +void mbl_mw_debug_read_stack_overflow_state(const MblMwMetaWearBoard *board, void *context, MblMwFnData handler) { + if (board->module_info.at(MBL_MW_MODULE_DEBUG).revision >= RES_MONITOR_REVISION) { + GET_DEBUG_STATE(board)->overflow_state_context = context; + GET_DEBUG_STATE(board)->overflow_state_handler = handler; + + uint8_t command[2]= {MBL_MW_MODULE_DEBUG, READ_REGISTER(ORDINAL(DebugRegister::STACK_OVERFLOW))}; + SEND_COMMAND; + } else { + handler(context, nullptr); + } +} + +void mbl_mw_debug_spoof_notification(const MblMwMetaWearBoard *board, const uint8_t *value, uint8_t length) { + vector command(value, value + length); + command.insert(command.begin(), {MBL_MW_MODULE_DEBUG, ORDINAL(DebugRegister::NOTIFICATION_SPOOF)}); + + send_command(board, command.data(), (uint8_t) command.size()); +} + +void mbl_mw_debug_send_command(const MblMwMetaWearBoard *board, const uint8_t *value, uint8_t length) { + send_command(board, value, length); +} + +MblMwDataSignal* mbl_mw_debug_get_key_register_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(DEBUG_KEY_REGISTER_RESPONSE_HEADER); +} + +void mbl_mw_debug_set_key_register(const MblMwMetaWearBoard *board, uint32_t value) { + uint8_t command[6]= {MBL_MW_MODULE_DEBUG, ORDINAL(DebugRegister::KEY_REGISTER)}; + memcpy(command + 2, &value, sizeof(uint32_t)); + SEND_COMMAND; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug_private.h new file mode 100644 index 0000000..6306d86 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug_private.h @@ -0,0 +1,4 @@ +#pragma once + +void init_debug_module(MblMwMetaWearBoard *board); +void free_debug_module(void *state); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event.cpp new file mode 100644 index 0000000..0db1d31 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event.cpp @@ -0,0 +1,166 @@ +#include "metawear/core/event.h" +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/platform/cpp/threadpool.h" + +#include "event_register.h" +#include "event_private.h" +#include "metawearboard_def.h" +#include "register.h" + +#include +#include + +using std::forward_as_tuple; +using std::make_shared; +using std::piecewise_construct; +using std::shared_ptr; +using std::static_pointer_cast; +using std::vector; + +#define GET_EVENT_STATE(board) static_pointer_cast(board->event_state) + +struct EventState { + shared_ptr record_cmd_task; + void *event_recorded_context; + MblMwFnEventPtrInt event_recorded_callback; + MblMwEvent* event_owner; + const EventDataParameter* data_token; + vector event_config; + + EventState(); +}; + +EventState::EventState() : event_recorded_context(nullptr), event_recorded_callback(nullptr), event_owner(nullptr), data_token(nullptr) { +} + +MblMwEvent::MblMwEvent(uint8_t** state_stream, MblMwMetaWearBoard *owner) : header(state_stream), owner(owner), remove(true) { + uint8_t n_cmds = **state_stream; + for (uint8_t i = 0; i < n_cmds; i++) { + event_command_ids.push_back(*(++(*state_stream))); + } + + (*state_stream)++; +} + +MblMwEvent::MblMwEvent(const ResponseHeader& header, MblMwMetaWearBoard *owner) : header(header), owner(owner), remove(true) { +} + +MblMwEvent::~MblMwEvent() { + if (remove) { + uint8_t command[3]= {MBL_MW_MODULE_EVENT, ORDINAL(EventRegister::REMOVE)}; + + for(auto it: event_command_ids) { + command[2]= it; + SEND_COMMAND_BOARD(owner); + } + } +} + +void MblMwEvent::serialize(vector& state) const { + header.serialize(state); + + state.push_back((uint8_t) event_command_ids.size()); + state.insert(state.end(), event_command_ids.begin(), event_command_ids.end()); +} + +static int32_t event_command_recorded(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state = GET_EVENT_STATE(board); + if (state->event_owner != nullptr) { + state->event_owner->event_command_ids.push_back(response[2]); + + if ((uint8_t)state->event_owner->event_command_ids.size() == state->event_owner->num_expected_cmds) { + state->record_cmd_task->cancel(); + + auto caller = state->event_owner; + state->event_owner = nullptr; + state->event_recorded_callback(state->event_recorded_context, caller, MBL_MW_STATUS_OK); + } + } + return MBL_MW_STATUS_OK; +} + +void init_event_module(MblMwMetaWearBoard* board) { + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_EVENT, ORDINAL(EventRegister::ENTRY)), + forward_as_tuple(event_command_recorded)); + + if (!board->event_state) { + board->event_state = make_shared(); + } +} + +void free_event_module(void *state) { + delete (EventState*) state; +} + +void mbl_mw_event_record_commands(MblMwEvent *event) { + auto state = GET_EVENT_STATE(event->owner); + + state->event_owner= event; + event->commands.clear(); + event->num_expected_cmds= 0; + state->event_config.assign({event->header.module_id, event->header.register_id, event->header.data_id}); +} + +void mbl_mw_event_end_record(MblMwEvent *event, void *context, MblMwFnEventPtrInt commands_recorded) { + auto state = GET_EVENT_STATE(event->owner); + + state->event_recorded_context= context; + state->event_recorded_callback= commands_recorded; + state->event_config.clear(); + state->record_cmd_task= ThreadPool::schedule([state, event](void) -> void { + state->event_owner = nullptr; + state->event_recorded_callback(state->event_recorded_context, event, MBL_MW_STATUS_ERROR_TIMEOUT); + }, event->commands.size() * event->owner->time_per_response); + + for(auto it: event->commands) { + send_command(event->owner, it.data(), (uint8_t) it.size()); + } +} + +MblMwMetaWearBoard* mbl_mw_event_get_owner(const MblMwEvent *event) { + return event->owner; +} + +bool record_command(const MblMwMetaWearBoard* board, const uint8_t* command, uint8_t len) { + auto state = GET_EVENT_STATE(board); + + if (state != nullptr && !state->event_config.empty()) { + state->event_owner->num_expected_cmds++; + vector event_entry = { MBL_MW_MODULE_EVENT, ORDINAL(EventRegister::ENTRY), + state->event_config.at(0), state->event_config.at(1), state->event_config.at(2), command[0], command[1], + (uint8_t)(len - 2) }; + + if (state->data_token != nullptr) { + uint8_t event_data[2] = { + (uint8_t)(0x01 | (state->data_token->data_length << 1) | (state->data_token->data_offset << 4)), + state->data_token->dest_offset + }; + event_entry.insert(event_entry.end(), event_data, event_data + sizeof(event_data)); + } + state->event_owner->commands.emplace_back(event_entry); + + vector event_parameters(command + 2, command + len); + uint8_t prefix[2] = { MBL_MW_MODULE_EVENT, ORDINAL(EventRegister::CMD_PARAMETERS) }; + event_parameters.insert(event_parameters.begin(), prefix, prefix + sizeof(prefix)); + state->event_owner->commands.emplace_back(event_parameters); + + return true; + } + return false; +} + +void set_data_token(MblMwMetaWearBoard* board, const EventDataParameter* token) { + GET_EVENT_STATE(board)->data_token = token; +} +void clear_data_token(MblMwMetaWearBoard* board) { + GET_EVENT_STATE(board)->data_token = nullptr;; +} + +void mbl_mw_event_remove_all(MblMwMetaWearBoard* board) { + for (auto it: board->module_events) { + it.second->event_command_ids.clear(); + } + uint8_t command[2]= {MBL_MW_MODULE_EVENT, ORDINAL(EventRegister::REMOVE_ALL)}; + SEND_COMMAND; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event_private.h new file mode 100644 index 0000000..087cdbd --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event_private.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#include "metawear/core/event_fwd.h" +#include "metawear/core/metawearboard_fwd.h" +#include "responseheader.h" + +struct EventDataParameter { + uint8_t data_length; + uint8_t data_offset; + uint8_t dest_offset; +}; + +struct MblMwEvent { + MblMwEvent(uint8_t** state_stream, MblMwMetaWearBoard *owner); + MblMwEvent(const ResponseHeader& header, MblMwMetaWearBoard* owner); + virtual ~MblMwEvent(); + + virtual void serialize(std::vector& state) const; + + std::vector event_command_ids; + ResponseHeader header; + + MblMwMetaWearBoard* const owner; + std::vector> commands; + uint8_t num_expected_cmds; + bool remove; +}; + +void init_event_module(MblMwMetaWearBoard* board); +void free_event_module(void *state); +bool record_command(const MblMwMetaWearBoard* board, const uint8_t* command, uint8_t len); +void set_data_token(MblMwMetaWearBoard* board, const EventDataParameter* token); +void clear_data_token(MblMwMetaWearBoard* board); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event_register.h new file mode 100644 index 0000000..81e1ece --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event_register.h @@ -0,0 +1,8 @@ +#pragma once + +enum class EventRegister : uint8_t { + ENTRY = 2, + CMD_PARAMETERS, + REMOVE, + REMOVE_ALL +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging.cpp new file mode 100644 index 0000000..c6de82a --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging.cpp @@ -0,0 +1,962 @@ +#include "metawear/core/logging.h" +#include "metawear/core/datasignal.h" +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/platform/cpp/async_creator.h" +#include "metawear/platform/cpp/threadpool.h" +#include "metawear/processor/cpp/dataprocessor_config.h" +#include "metawear/processor/cpp/dataprocessor_private.h" +#include "metawear/processor/cpp/dataprocessor_register.h" + +#include "anonymous_datasignal_private.h" +#include "datasignal_private.h" +#include "logging_private.h" +#include "logging_register.h" +#include "metawearboard_def.h" +#include "register.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +#define GET_LOGGER_STATE(board) static_pointer_cast(board->logger_state) + +const uint8_t REVISION_EXTENDED_LOGGING= 2, MMS_REVISION= 3, ENTRY_ID_MASK= 0x1f, RESET_UID_MASK= 0x7, + LOG_ENTRY_SIZE= (uint8_t) sizeof(uint32_t), ROOT_SIGNAL_INDEX= 0xff; +const double TICK_TIME_STEP= (48.0 / 32768.0) * 1000.0; ///< milliseconds + +const ResponseHeader + LOGGING_TIME_RESPONSE_HEADER(MBL_MW_MODULE_LOGGING, READ_REGISTER(ORDINAL(LoggingRegister::TIME))), + LOGGING_LENGTH_RESPONSE_HEADER(MBL_MW_MODULE_LOGGING, READ_REGISTER(ORDINAL(LoggingRegister::LENGTH))), + LOGGING_READOUT_NOTIFY_HEADER(MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::READOUT_NOTIFY)), + LOGGING_READOUT_PAGE_COMPLETED_HEADER(MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::READOUT_PAGE_COMPLETED)); + +static int32_t logging_response_readout_progress(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len); + +struct TimeReference { + int64_t epoch; + uint8_t reset_uid; + + TimeReference(uint8_t** state_stream, uint8_t format); + TimeReference(int64_t epoch, uint8_t reset_uid); + void serialize(vector& state) const; +}; + +struct MblMwDataLogger; +struct LoggerState : public AsyncCreator { + unordered_map log_time_references; + unordered_map latest_tick, rollback_timestamps; + unordered_map data_loggers; + unordered_map identifiers; + unordered_map placeholder; + unordered_map nRemainingLoggers; + vector anonymous_signals; + stack fuser_ids; + stack> fuser_configs; + MblMwDataLogger* next_logger; + MblMwLogDownloadHandler log_download_handler; + MblMwRawLogDownloadHandler raw_log_download_handler; + float log_download_notify_progress; + uint32_t n_log_entries; + uint8_t latest_reset_uid, queryLogId; + bool state_signal; + + LoggerState(); + + void clear_data_loggers(); +}; + +struct MblMwDataLogger : public MblMwAnonymousDataSignal { + MblMwDataLogger(uint8_t** state_stream, uint8_t format, MblMwMetaWearBoard* board); + MblMwDataLogger(MblMwDataSignal* source, void *context, MblMwFnDataLoggerPtr logger_ready); + + virtual void subscribe(void *context, MblMwFnData data_handler); + virtual const char* get_identifier() const { + auto state = GET_LOGGER_STATE(source->owner); + + if (!state->identifiers.count(this)) { + stringstream stream; + MblMwDataSignal* current = source; + MblMwDataProcessor* processor; + stack parts; + + do { + parts.push(current); + if ((processor = dynamic_cast(current)) != nullptr) { + current = processor->parent(); + } else if (current->header.module_id == MBL_MW_MODULE_DATA_PROCESSOR && CLEAR_READ(current->header.register_id) == ORDINAL(DataProcessorRegister::STATE)) { + ResponseHeader header(MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY), current->header.data_id); + current = dynamic_cast(current->owner->module_events.at(header))->parent(); + } else { + current = nullptr; + } + } while(current != nullptr); + + bool first = true; + if ((processor = dynamic_cast(parts.top())) != nullptr) { + processor->input->create_uri(stream); + first = false; + } + while(!parts.empty()) { + if (!first) { + stream << ":"; + } + parts.top()->create_uri(stream); + + first = false; + parts.pop(); + } + + state->identifiers.emplace(this, stream.str()); + } + return state->identifiers[this].c_str(); + } + + void add_entry_id(uint8_t id, bool anonymous); + void process_log_data(uint8_t id, int64_t epoch, uint32_t data); + void serialize(vector& state) const; + + inline uint8_t get_id() const { + return entry_ids.front(); + } + + MblMwDataSignal* source; + uint8_t n_req_entries; + void *data_context; + MblMwFnData data_handler; + void *logger_context; + MblMwFnDataLoggerPtr logger_ready; + vector entry_ids; + unordered_map> entries; +}; + +static int32_t logging_response_entry_id_received(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + GET_LOGGER_STATE(board)->next_logger->add_entry_id(response[2], false); + return 0; +} + +static MblMwDataSignal* guessLogSource(MblMwMetaWearBoard* board, ResponseHeader& key, uint8_t offset, uint8_t length) { + key.disable_silent(); + + vector possible; + auto source = dynamic_cast(board->module_events.at(key)); + + possible.push_back(source); + possible.insert(possible.end(), source->components.begin(), source->components.end()); + + MblMwDataSignal* original = nullptr; + bool multiple = false; + for(auto it: possible) { + if (it->length() > 4) { + original = it; + multiple = true; + } + } + + if (multiple) { + auto state = GET_LOGGER_STATE(board); + if (offset == 0 && length > LOG_ENTRY_SIZE) { + return original; + } + if (!state->placeholder.count(key) && length == LOG_ENTRY_SIZE) { + state->placeholder[key] = length; + return original; + } + if (state->placeholder.count(key)) { + uint8_t newLength = (uint8_t) (state->placeholder[key] + length); + if (newLength == original->length()) { + state->placeholder.erase(key); + } + return original; + } + } + + for(auto it: possible) { + if (it->offset == offset && it->length() == length) { + return it; + } + } + return nullptr; +} + +static void queue_next_logger(MblMwMetaWearBoard* board) { + auto state = GET_LOGGER_STATE(board); + state->timeout->cancel(); + + state->queryLogId++; + if (state->queryLogId < board->module_info.at(MBL_MW_MODULE_LOGGING).extra[0]) { + state->pending_fns.push([=](void) -> void { + state->timeout= ThreadPool::schedule([state, board](void) -> void { + board->anon_signals_created(board->anon_signals_context, board, nullptr, MBL_MW_STATUS_ERROR_TIMEOUT); + state->create_next(true); + }, board->time_per_response); + + uint8_t command[3]= {MBL_MW_MODULE_LOGGING, READ_REGISTER(ORDINAL(LoggingRegister::TRIGGER)), state->queryLogId}; + SEND_COMMAND; + }); + } else { + vector sorted; + for (auto it: state->data_loggers) { + sorted.push_back(it.first); + } + sort(sorted.begin(), sorted.end()); + + state->anonymous_signals.clear(); + for(auto it: sorted) { + auto val = state->data_loggers[it]; + auto pos = find(begin(state->anonymous_signals), end(state->anonymous_signals), val); + if (pos == end(state->anonymous_signals)) { + state->anonymous_signals.push_back(val); + } + } + + board->anon_signals_created(board->anon_signals_context, board, state->anonymous_signals.data(), (uint32_t) state->anonymous_signals.size()); + } + state->create_next(true); +} + +static void log_source_discovered(shared_ptr state, MblMwDataSignal* source, uint8_t offset) { + if (state->state_signal) { + source = dynamic_cast(source)->state; + } + + MblMwDataProcessor const* processor = dynamic_cast(source); + if (processor != nullptr) { + MblMwDataSignal const* last; + while(processor != nullptr) { + last = processor->input; + processor = dynamic_cast(last); + } + } + + if (!state->nRemainingLoggers.count(source->header) && source->length() > LOG_ENTRY_SIZE) { + state->nRemainingLoggers[source->header] = (int8_t) ceil((float) (source->length() / LOG_ENTRY_SIZE)); + } + + MblMwDataLogger* logger = nullptr; + for(auto it: state->data_loggers) { + auto other = it.second->source; + if (other->header == source->header && other->offset == source->offset && + other->is_signed == source->is_signed && other->n_channels == source->n_channels && other->channel_size == source->channel_size) { + logger = it.second; + break; + } + } + + if (logger == nullptr || (offset != 0 && !state->nRemainingLoggers.count(source->header))) { + logger = new MblMwDataLogger(source, nullptr, nullptr); + } + logger->add_entry_id(state->queryLogId, true); + state->data_loggers[state->queryLogId] = logger; + + if (state->nRemainingLoggers.count(source->header)) { + state->nRemainingLoggers[source->header]--; + if (state->nRemainingLoggers[source->header] < 0) { + state->nRemainingLoggers.erase(source->header); + } + } + + queue_next_logger(source->owner); +} + +static void processor_synced(MblMwMetaWearBoard* board, stack& entries) { + auto type = guessLogSource(board, entries.top().source, entries.top().offset, entries.top().length); + auto state = GET_LOGGER_STATE(board); + auto fill_processor = [board](MblMwDataSignal* parent, const ProcessorEntry& entry) { + auto next = MblMwDataProcessor::transform(parent, entry.config); + next->header.data_id = entry.id; + + if (board->module_events.count(next->header)) { + auto temp = board->module_events.at(next->header); + delete next; + + next = dynamic_cast(temp); + } else { + board->module_events.emplace(next->header, next); + } + + if (parent->header.module_id == MBL_MW_MODULE_DATA_PROCESSOR && CLEAR_READ(parent->header.register_id) == ORDINAL(DataProcessorRegister::NOTIFY)) { + next->parent_id = parent->header.data_id; + } + if (next->state != nullptr) { + next->state->header.data_id = entry.id; + board->module_events.emplace(next->state->header, next->state); + } + + return next; + }; + + while(!entries.empty()) { + auto config = entries.top().config; + if (config[0] == 0x1b) { + for(uint8_t i = 0; i < (config[1] & 0x1f); i++) { + state->fuser_ids.push(config[i + 2]); + } + state->fuser_configs.push(make_tuple(type, entries.top())); + } else { + type = fill_processor(type, entries.top()); + } + entries.pop(); + } + + if (state->fuser_ids.empty()) { + while(!state->fuser_configs.empty()) { + auto top = state->fuser_configs.top(); + type = MblMwDataProcessor::transform(get<0>(top), get<1>(top).config); + type->header.data_id = get<1>(top).id; + + fill_processor(type, get<1>(top)); + state->fuser_configs.pop(); + } + log_source_discovered(GET_LOGGER_STATE(board), type, 0); + } else { + auto id = state->fuser_ids.top(); + state->fuser_ids.pop(); + + sync_processor_chain(board, id, processor_synced); + } +} + +static int32_t logging_response_read_entry_id(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state = GET_LOGGER_STATE(board); + + if (len > 2) { + uint8_t offset = (uint8_t) (response[5] & 0x1f), length = (uint8_t) (((response[5] >> 5) & 0x3) + 1); + ResponseHeader key(response[2], response[3], response[4]); + + state->state_signal = key.module_id == MBL_MW_MODULE_DATA_PROCESSOR && CLEAR_READ(key.register_id) == ORDINAL(DataProcessorRegister::STATE); + if (key.module_id == MBL_MW_MODULE_DATA_PROCESSOR && (key.register_id == ORDINAL(DataProcessorRegister::NOTIFY) || state->state_signal)) { + sync_processor_chain(board, key.data_id, processor_synced); + } else { + log_source_discovered(state, guessLogSource(board, key, offset, length), offset); + } + } else { + queue_next_logger(board); + } + + return 0; +} + +static int32_t logging_response_length_received(MblMwMetaWearBoard *board, uint32_t log_entries) { + auto state= GET_LOGGER_STATE(board); + state->n_log_entries = log_entries; + + // If there are no entires we won't get any responses, so end the download now + // by forcing a callback on the readout progress with 0 remaining entries + if (state->n_log_entries == 0) { + state->latest_tick.clear(); + state->rollback_timestamps.clear(); + uint8_t readoutResponse[6] = {0}; + return logging_response_readout_progress(board, readoutResponse, sizeof(readoutResponse)); + } + + uint32_t n_entries_notify= state->n_log_entries * state->log_download_notify_progress; + vector command= { MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::READOUT) }; + command.insert(command.end(), (uint8_t*) &state->n_log_entries, (uint8_t*) &state->n_log_entries + 4); + command.insert(command.end(), (uint8_t*) &n_entries_notify, (uint8_t*) &n_entries_notify + 4); + send_command(board, command.data(), (uint8_t) command.size()); + + return 0; +} + +static TimeReference& mbl_mw_logger_lookup_reset_uid(const MblMwMetaWearBoard* board, uint8_t reset_uid) { + auto logger_state = GET_LOGGER_STATE(board); + if (logger_state->log_time_references.count(reset_uid)) { + return logger_state->log_time_references.at(reset_uid); + } + // No valid reset uid time base found. This means we had multiple unexpected resets, + // so come up with a best guess by working backwards to find a previous reset uid base. + for (uint8_t prev_uid = (reset_uid - 1) & RESET_UID_MASK; prev_uid != reset_uid; prev_uid = (prev_uid - 1) & RESET_UID_MASK) { + if (logger_state->log_time_references.count(prev_uid)) { + // Copy the previous one + TimeReference prev_reference = logger_state->log_time_references.at(prev_uid); + prev_reference.reset_uid = reset_uid; + logger_state->log_time_references.emplace(reset_uid, prev_reference); + return logger_state->log_time_references.at(reset_uid); + } + } + // Nothing to go on just create a new one + logger_state->log_time_references.emplace(piecewise_construct, forward_as_tuple(reset_uid), + forward_as_tuple(0, reset_uid)); + return logger_state->log_time_references.at(reset_uid); +} + +static int64_t calculate_epoch_inner(shared_ptr state, uint32_t tick, TimeReference& reference) { + state->latest_tick[reference.reset_uid]= tick; + return reference.epoch + static_cast(round((double)tick * TICK_TIME_STEP)); +} + +static int32_t logging_response_readout_notify(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto parse_response= [&board, &response](uint8_t offset) -> void { + auto state= GET_LOGGER_STATE(board); + uint8_t entry_id= response[offset] & ENTRY_ID_MASK, reset_uid= (response[offset] & ~ENTRY_ID_MASK) >> 5; + auto entry_tick = (uint32_t*) (response + offset + 1), data = entry_tick + 1; + + if (!state->rollback_timestamps.count(reset_uid) || state->rollback_timestamps.at(reset_uid) < *entry_tick) { + auto realtime = calculate_epoch_inner(state, *entry_tick, mbl_mw_logger_lookup_reset_uid(board, reset_uid)); + if (state->data_loggers.count(entry_id)) { + state->data_loggers.at(entry_id)->process_log_data(entry_id, realtime, *data); + } else if (state->log_download_handler.received_unknown_entry != nullptr) { + state->log_download_handler.received_unknown_entry(state->log_download_handler.context, entry_id, realtime, (const uint8_t*) data, sizeof(*data)); + } + } + }; + + parse_response(2); + if (len == 20) { + parse_response(11); + } + + return 0; +} + +static int32_t raw_logging_response_readout_notify(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto parse_response= [&board, &response](uint8_t offset) -> void { + auto state= GET_LOGGER_STATE(board); + uint8_t entry_id = response[offset] & ENTRY_ID_MASK; + uint8_t reset_uid = (response[offset] & ~ENTRY_ID_MASK) >> 5; + uint32_t entry_tick; + memcpy(&entry_tick, (response + offset + 1), 4); + uint32_t data; + memcpy(&data, (response + offset + 5), 4); + if (state->raw_log_download_handler.received_entry != nullptr) { + state->raw_log_download_handler.received_entry(state->raw_log_download_handler.context, entry_id, reset_uid, entry_tick, data); + } + }; + + parse_response(2); + if (len == 20) { + parse_response(11); + } + + return 0; +} + +static int32_t logging_response_readout_progress(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state= GET_LOGGER_STATE(board); + uint32_t entries_left; + memcpy(&entries_left, response + 2, min(len - 2, 4)); + + if (entries_left == 0) { + state->latest_tick.clear(); + state->rollback_timestamps.clear(); + } + if (state->log_download_handler.received_progress_update != nullptr) { + state->log_download_handler.received_progress_update(state->log_download_handler.context, entries_left, state->n_log_entries); + } + if (state->raw_log_download_handler.received_progress_update != nullptr) { + state->raw_log_download_handler.received_progress_update(state->raw_log_download_handler.context, entries_left, state->n_log_entries); + } + return 0; +} + +static int32_t logging_response_page_completed(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + uint8_t command[2]= { MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::READOUT_PAGE_CONFIRM) }; + SEND_COMMAND; + return 0; +} + +static int32_t raw_logging_response_page_completed(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state= GET_LOGGER_STATE(board); + if (state->raw_log_download_handler.logging_page_completed != nullptr) { + state->raw_log_download_handler.logging_page_completed(state->raw_log_download_handler.context, board, [](const MblMwMetaWearBoard* board) { + uint8_t command[2]= { MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::READOUT_PAGE_CONFIRM) }; + SEND_COMMAND; + }); + } + return 0; +} + +TimeReference::TimeReference(uint8_t** state_stream, uint8_t format) { + if (format <= ORDINAL(SerializationFormat::SIGNAL_COMPONENT)) { + milliseconds epoch(*((int64_t*) *state_stream)); + auto timestamp= time_point{epoch}; + *state_stream += sizeof(int64_t); + + uint32_t tick; + memcpy(&tick, *state_stream, sizeof(uint32_t)); + *state_stream += sizeof(uint32_t); + + reset_uid = **state_stream; + + (*state_stream)++; + + this->epoch = duration_cast(timestamp.time_since_epoch()).count() - static_cast(round((double)tick * TICK_TIME_STEP)); + } else { + memcpy(&epoch, *state_stream, sizeof(int64_t)); + *state_stream += sizeof(int64_t); + + reset_uid = **state_stream; + + (*state_stream)++; + } +} + +TimeReference::TimeReference(int64_t epoch, uint8_t reset_uid) : epoch(epoch), reset_uid(reset_uid) { +} + +void TimeReference::serialize(vector& state) const { + state.insert(state.end(), (uint8_t*) &epoch, ((uint8_t*) &epoch) + sizeof(epoch)); + state.push_back(reset_uid); +} + +MblMwDataLogger::MblMwDataLogger(uint8_t** state_stream, uint8_t format, MblMwMetaWearBoard* board) : + data_context(nullptr), data_handler(nullptr), logger_context(nullptr), logger_ready(nullptr) { + uint8_t signal_index; + + if (format >= ORDINAL(SerializationFormat::SIGNAL_COMPONENT)) { + signal_index = **state_stream; + (*state_stream)++; + } else { + signal_index = ROOT_SIGNAL_INDEX; + } + + ResponseHeader source_header(state_stream); + source_header.disable_silent(); + + auto root = dynamic_cast(board->module_events.at(source_header)); + source = (signal_index == ROOT_SIGNAL_INDEX) ? root : root->components.at(signal_index); + + uint8_t n_entry_ids = **state_stream; + for (uint8_t i = 0; i < n_entry_ids; i++) { + uint8_t id = *(++(*state_stream)); + entry_ids.push_back(id); + entries.emplace(id, queue()); + } + + (*state_stream)++; +} + +MblMwDataLogger::MblMwDataLogger(MblMwDataSignal* source, void *context, MblMwFnDataLoggerPtr logger_ready) : + source(source), n_req_entries((source->length() - 1) / sizeof(uint32_t) + 1), + data_context(nullptr), data_handler(nullptr), logger_context(context), logger_ready(logger_ready) { +} + +void MblMwDataLogger::subscribe(void *context, MblMwFnData data_handler) { + this->data_context = context; + this->data_handler = data_handler; +} + +void MblMwDataLogger::add_entry_id(uint8_t id, bool anonymous) { + entry_ids.push_back(id); + entries.emplace(id, queue()); + + if (!anonymous && (uint8_t) entry_ids.size() == n_req_entries) { + auto state= GET_LOGGER_STATE(source->owner); + + state->timeout->cancel(); + + for(auto it: entry_ids) { + state->data_loggers[it]= this; + } + state->next_logger = nullptr; + + logger_ready(logger_context, this); + + state->create_next(true); + } +} + +void MblMwDataLogger::process_log_data(uint8_t id, int64_t epoch, uint32_t data) { + entries.at(id).push(data); + + bool ready= true; + for(auto it: entries) { + ready&= !it.second.empty(); + } + if (ready) { + vector merged; + for(auto it: entry_ids) { + uint8_t *data= (uint8_t*) &entries.at(it).front(); + merged.insert(merged.end(), data, data + 4); + entries.at(it).pop(); + } + + MblMwData* data = data_response_converters.at(source->interpreter)(true, source, merged.data(), (uint8_t) merged.size()); + data->epoch= epoch; + + MblMwFnData unhandled_callback; + if (data_handler != nullptr) { + data_handler(data_context, data); + } else if ((unhandled_callback= GET_LOGGER_STATE(source->owner)->log_download_handler.received_unhandled_entry) != nullptr) { + unhandled_callback(GET_LOGGER_STATE(source->owner)->log_download_handler.context, data); + } + + free_data(source, data); + } +} + +void MblMwDataLogger::serialize(vector& state) const { + ResponseHeader copy(source->header); + copy.disable_silent(); + + auto root = dynamic_cast(source->owner->module_events.at(copy)); + if (source == root) { + state.push_back(ROOT_SIGNAL_INDEX); + } else { + uint8_t i = 0; + for (auto it : root->components) { + if (it == source) break; + i++; + } + + state.push_back(i); + } + source->header.serialize(state); + + state.push_back((uint8_t)entry_ids.size()); + state.insert(state.end(), entry_ids.begin(), entry_ids.end()); +} + +LoggerState::LoggerState() : next_logger(nullptr) { } + +void LoggerState::clear_data_loggers() { + unordered_set unique_loggables; + for (auto it : data_loggers) { + unique_loggables.insert(it.second); + } + + for(auto it: unique_loggables) { + delete it; + } + + data_loggers.clear(); + identifiers.clear(); +} + +void init_logging(MblMwMetaWearBoard *board) { + if (!board->module_events.count(LOGGING_TIME_RESPONSE_HEADER)) { + board->module_events[LOGGING_TIME_RESPONSE_HEADER] = new MblMwDataSignal(LOGGING_TIME_RESPONSE_HEADER, board, + DataInterpreter::LOGGING_TIME, 1, 5, 0, 0); + } + board->responses[LOGGING_TIME_RESPONSE_HEADER] = response_handler_data_no_id; + + if (!board->module_events.count(LOGGING_LENGTH_RESPONSE_HEADER)) { + board->module_events[LOGGING_LENGTH_RESPONSE_HEADER] = new MblMwDataSignal(LOGGING_LENGTH_RESPONSE_HEADER, board, + DataInterpreter::UINT32, 1, 4, 0, 0); + } + board->responses[LOGGING_LENGTH_RESPONSE_HEADER] = response_handler_data_no_id; + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::TRIGGER)), + forward_as_tuple(logging_response_entry_id_received)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_LOGGING, READ_REGISTER(ORDINAL(LoggingRegister::TRIGGER))), + forward_as_tuple(logging_response_read_entry_id)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::READOUT_PROGRESS)), + forward_as_tuple(logging_response_readout_progress)); + + if (!board->logger_state) { + board->logger_state = make_shared(); + } +} + +void tear_down_logging(void *state, bool preserve_memory) { + auto logging_state= (LoggerState*) state; + + if (logging_state != nullptr) { + logging_state->clear_data_loggers(); + if (!preserve_memory) { + delete logging_state; + } + } +} + +void disconnect_logging(MblMwMetaWearBoard* board) { + auto state = GET_LOGGER_STATE(board); + + if (state != nullptr) { + state->pending_fns.clear(); + for(auto it: state->latest_tick) { + state->rollback_timestamps[it.first] = it.second; + } + } +} + +void mbl_mw_logging_start(const MblMwMetaWearBoard* board, uint8_t overwrite) { + uint8_t command[3]= {MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::CIRCULAR_BUFFER), (uint8_t) (overwrite ? 1 : 0)}; + SEND_COMMAND; + + command[1]= ORDINAL(LoggingRegister::ENABLE); + command[2]= 0x1; + SEND_COMMAND; +} + +void mbl_mw_logging_stop(const MblMwMetaWearBoard* board) { + uint8_t command[3]= {MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::ENABLE), 0}; + SEND_COMMAND; +} + +void mbl_mw_logging_flush_page(const MblMwMetaWearBoard* board) { + if (board->module_info.at(MBL_MW_MODULE_LOGGING).revision == MMS_REVISION) { + uint8_t command[3]= {MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::PAGE_FLUSH), 1}; + SEND_COMMAND; + } +} + +void mbl_mw_logging_clear_entries(const MblMwMetaWearBoard* board) { + if (board->module_info.at(MBL_MW_MODULE_LOGGING).revision == REVISION_EXTENDED_LOGGING) { + uint8_t command[3]= {MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::READOUT_PAGE_COMPLETED), 1}; + SEND_COMMAND; + } + + uint8_t command[6]= {MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::REMOVE_ENTRIES), 0xff, 0xff, 0xff, 0xff}; + SEND_COMMAND; +} + +void mbl_mw_logging_download_common(MblMwMetaWearBoard* board, uint8_t n_notifies) { + auto state= GET_LOGGER_STATE(board); + state->log_download_notify_progress= n_notifies ? 1.0 / n_notifies : 0; + + uint8_t command[3]= {MBL_MW_MODULE_LOGGING}; + if (board->module_info.at(MBL_MW_MODULE_LOGGING).revision == REVISION_EXTENDED_LOGGING) { + command[1]= ORDINAL(LoggingRegister::READOUT_PAGE_COMPLETED); + command[2]= 0x1; + SEND_COMMAND; + } + + command[1]= ORDINAL(LoggingRegister::READOUT_NOTIFY); + command[2]= 0x1; + SEND_COMMAND; + + MblMwDataSignal *signal = mbl_mw_logging_get_length_data_signal(board); + mbl_mw_datasignal_subscribe(signal, board, [](void *context, const MblMwData* data) { + MblMwMetaWearBoard* board = static_cast(context); + mbl_mw_datasignal_unsubscribe(mbl_mw_logging_get_length_data_signal(board)); + logging_response_length_received(board, *static_cast(data->value)); + }); + mbl_mw_datasignal_read(signal); +} + +void mbl_mw_logging_download(MblMwMetaWearBoard* board, uint8_t n_notifies, const MblMwLogDownloadHandler* handler) { + board->responses[LOGGING_READOUT_NOTIFY_HEADER] = logging_response_readout_notify; + board->responses[LOGGING_READOUT_PAGE_COMPLETED_HEADER] = logging_response_page_completed; + + auto state= GET_LOGGER_STATE(board); + uint8_t command[3]= {MBL_MW_MODULE_LOGGING}; + + if (handler != nullptr) { + state->log_download_handler = *handler; + + command[1]= ORDINAL(LoggingRegister::READOUT_PROGRESS); + command[2]= 0x1; + SEND_COMMAND; + } else { + memset(&state->log_download_handler, 0, sizeof(MblMwLogDownloadHandler)); + } + memset(&state->raw_log_download_handler, 0, sizeof(MblMwRawLogDownloadHandler)); + + mbl_mw_logging_download_common(board, n_notifies); +} + +void mbl_mw_logging_raw_download(MblMwMetaWearBoard* board, uint8_t n_notifies, const MblMwRawLogDownloadHandler* handler) { + board->responses[LOGGING_READOUT_NOTIFY_HEADER] = raw_logging_response_readout_notify; + board->responses[LOGGING_READOUT_PAGE_COMPLETED_HEADER] = raw_logging_response_page_completed; + + auto state= GET_LOGGER_STATE(board); + uint8_t command[3]= {MBL_MW_MODULE_LOGGING}; + + if (handler != nullptr) { + state->raw_log_download_handler = *handler; + + command[1]= ORDINAL(LoggingRegister::READOUT_PROGRESS); + command[2]= 0x1; + SEND_COMMAND; + } else { + memset(&state->raw_log_download_handler, 0, sizeof(MblMwRawLogDownloadHandler)); + } + memset(&state->log_download_handler, 0, sizeof(MblMwLogDownloadHandler)); + + mbl_mw_logging_download_common(board, n_notifies); +} + +uint8_t mbl_mw_logger_get_id(const MblMwDataLogger* logger) { + return logger->get_id(); +} + +MblMwDataSignal* mbl_mw_logger_get_signal(const MblMwDataLogger* logger) { + return logger->source; +} + +MblMwDataLogger* mbl_mw_logger_lookup_id(const MblMwMetaWearBoard* board, uint8_t id) { + auto logger_state = GET_LOGGER_STATE(board); + return logger_state->data_loggers.count(id) ? logger_state->data_loggers.at(id) : nullptr; +} + +void mbl_mw_logger_remove(MblMwDataLogger* loggable) { + auto state = GET_LOGGER_STATE(loggable->source->owner); + + sort(loggable->entry_ids.begin(), loggable->entry_ids.end()); + for (auto it : loggable->entry_ids) { + state->data_loggers.erase(it); + uint8_t command[3] = { MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::REMOVE), it }; + SEND_COMMAND_BOARD(loggable->source->owner); + } + + delete loggable; +} + +void mbl_mw_logger_subscribe(MblMwDataLogger* loggable, void *context, MblMwFnData received_data) { + loggable->data_context = context; + loggable->data_handler = received_data; +} + +const char* mbl_mw_logger_generate_identifier(const MblMwDataLogger* signal) { + return signal->get_identifier(); +} + +void mbl_mw_datasignal_log(MblMwDataSignal *signal, void *context, MblMwFnDataLoggerPtr logger_ready) { + auto state= GET_LOGGER_STATE(signal->owner); + + state->pending_fns.push([=](void) -> void { + state->next_logger= new MblMwDataLogger(signal, context, logger_ready); + state->timeout= ThreadPool::schedule([context, state, logger_ready](void) -> void { + delete state->next_logger; + state->next_logger = nullptr; + + logger_ready(context, nullptr); + state->create_next(true); + }, state->next_logger->n_req_entries * signal->owner->time_per_response); + + auto entries= state->next_logger->n_req_entries; + uint8_t remainder= signal->length(); + for(uint8_t i= 0; i < entries; i++, remainder-= LOG_ENTRY_SIZE) { + uint8_t entry_size= min(remainder, LOG_ENTRY_SIZE), entry_offset= LOG_ENTRY_SIZE * i + signal->offset; + uint8_t command[6]= {MBL_MW_MODULE_LOGGING, ORDINAL(LoggingRegister::TRIGGER), signal->header.module_id, signal->header.register_id, + signal->header.data_id, (uint8_t) ((entry_size - 1) << 5 | entry_offset)}; + SEND_COMMAND_BOARD(signal->owner); + } + }); + state->create_next(false); +} + +void serialize_logging(const MblMwMetaWearBoard* board, std::vector& state) { + auto logger_state= GET_LOGGER_STATE(board); + + { + vector sorted_keys; + for (auto it : logger_state->log_time_references) { + sorted_keys.push_back(it.first); + } + sort(sorted_keys.begin(), sorted_keys.end()); + + state.push_back((uint8_t)logger_state->log_time_references.size()); + for (auto it : sorted_keys) { + logger_state->log_time_references.at(it).serialize(state); + } + } + + { + vector sorted_keys; + unordered_set unique_loggers; + for (auto it : logger_state->data_loggers) { + sorted_keys.push_back(it.first); + unique_loggers.insert(it.second); + } + sort(sorted_keys.begin(), sorted_keys.end()); + + state.push_back((uint8_t) unique_loggers.size()); + unique_loggers.clear(); + for (auto it : sorted_keys) { + auto current = logger_state->data_loggers.at(it); + if (!unique_loggers.count(current)) { + unique_loggers.insert(current); + current->serialize(state); + } + } + } +} + +void deserialize_logging(MblMwMetaWearBoard* board, uint8_t format, uint8_t** state_stream) { + if (board->logger_state) { + GET_LOGGER_STATE(board)->clear_data_loggers(); + } else { + board->logger_state = make_shared(); + } + + auto saved_log_state = GET_LOGGER_STATE(board); + + uint8_t n_refs = **state_stream; + (*state_stream)++; + for (uint8_t i = 0; i < n_refs; i++) { + TimeReference reference(state_stream, format); + saved_log_state->log_time_references.emplace(reference.reset_uid, reference); + } + + uint8_t n_loggers = **state_stream; + (*state_stream)++; + for (uint8_t i = 0; i < n_loggers; i++) { + MblMwDataLogger* saved_loggable = new MblMwDataLogger(state_stream, format, board); + + for (auto it : saved_loggable->entry_ids) { + saved_log_state->data_loggers[it] = saved_loggable; + } + } +} + +int64_t calculate_epoch(const MblMwMetaWearBoard* board, uint32_t tick) { + return calculate_epoch_inner(GET_LOGGER_STATE(board), tick, mbl_mw_logger_lookup_reset_uid(board, GET_LOGGER_STATE(board)->latest_reset_uid)); +} + +void query_active_loggers(MblMwMetaWearBoard* board) { + auto state= GET_LOGGER_STATE(board); + state->clear_data_loggers(); + state->anonymous_signals.clear(); + state->queryLogId = 0; + + state->pending_fns.push([=](void) -> void { + state->timeout= ThreadPool::schedule([state, board](void) -> void { + board->anon_signals_created(board->anon_signals_context, board, nullptr, MBL_MW_STATUS_ERROR_TIMEOUT); + state->create_next(true); + }, board->time_per_response); + + uint8_t command[3]= {MBL_MW_MODULE_LOGGING, READ_REGISTER(ORDINAL(LoggingRegister::TRIGGER)), state->queryLogId}; + SEND_COMMAND; + }); + state->create_next(false); +} + +MblMwDataSignal* mbl_mw_logging_get_length_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(LOGGING_LENGTH_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_logging_get_time_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(LOGGING_TIME_RESPONSE_HEADER); +} + +uint8_t mbl_mw_logging_get_latest_reset_uid(const MblMwMetaWearBoard* board) { + return GET_LOGGER_STATE(board)->latest_reset_uid; +} + +void mbl_mw_logging_set_latest_reset_uid(const MblMwMetaWearBoard* board, uint8_t reset_uid) { + GET_LOGGER_STATE(board)->latest_reset_uid = reset_uid; +} + +int64_t mbl_mw_logging_get_reference_time(const MblMwMetaWearBoard *board, uint8_t reset_uid) { + auto logger_state = GET_LOGGER_STATE(board); + if (logger_state->log_time_references.count(reset_uid)) { + return logger_state->log_time_references.at(reset_uid).epoch; + } + return -1; +} + +void mbl_mw_logging_set_reference_time(const MblMwMetaWearBoard *board, uint8_t reset_uid, int64_t reference_epoch) { + auto logger_state = GET_LOGGER_STATE(board); + if (logger_state->log_time_references.count(reset_uid)) { + logger_state->log_time_references.at(reset_uid).epoch = reference_epoch; + } else { + logger_state->log_time_references.emplace(piecewise_construct, forward_as_tuple(reset_uid), + forward_as_tuple(reference_epoch, reset_uid)); + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging_private.h new file mode 100644 index 0000000..85aab1c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging_private.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include "metawear/core/anonymous_datasignal_fwd.h" + +extern const double TICK_TIME_STEP; + +void init_logging(MblMwMetaWearBoard *board); +void tear_down_logging(void *state, bool preserve_memory); +void serialize_logging(const MblMwMetaWearBoard* board, std::vector& state); +void deserialize_logging(MblMwMetaWearBoard* board, uint8_t format, uint8_t** state_stream); +void disconnect_logging(MblMwMetaWearBoard* board); +void query_active_loggers(MblMwMetaWearBoard* board); +int64_t calculate_epoch(const MblMwMetaWearBoard* board, uint32_t tick); +void mbl_mw_logging_set_latest_reset_uid(const MblMwMetaWearBoard* board, uint8_t reset_uid); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging_register.h new file mode 100644 index 0000000..9f0a04b --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging_register.h @@ -0,0 +1,20 @@ +#pragma once + +#include "responseheader.h" + +enum class LoggingRegister : uint8_t { + ENABLE = 1, + TRIGGER, + REMOVE, + TIME, + LENGTH, + READOUT, + READOUT_NOTIFY, + READOUT_PROGRESS, + REMOVE_ENTRIES, + REMOVE_ALL, + CIRCULAR_BUFFER, + READOUT_PAGE_COMPLETED = 0xd, + READOUT_PAGE_CONFIRM, + PAGE_FLUSH = 0x10, +}; \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro.cpp new file mode 100644 index 0000000..7d4c44e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro.cpp @@ -0,0 +1,130 @@ +#include "constant.h" +#include "metawearboard_def.h" +#include "register.h" + +#include "macro_private.h" +#include "macro_register.h" +#include "metawear/core/macro.h" +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/platform/cpp/threadpool.h" + +#include +#include + +using std::forward_as_tuple; +using std::make_shared; +using std::piecewise_construct; +using std::static_pointer_cast; +using std::vector; + +#define GET_MACRO_STATE(board) static_pointer_cast(board->macro_state) + +const size_t PARTIAL_LENGTH = 2; +const ResponseHeader MACRO_BEGIN(MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::BEGIN)); + +struct MacroState { + MacroState(); + + MblMwFnBoardPtrInt commands_recorded; + void *commands_recorded_context; + vector> commands; + bool is_recording; + uint8_t exec_on_boot; +}; + +MacroState::MacroState() : is_recording(false) { } + +static int32_t macro_add_cmd_response(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state = GET_MACRO_STATE(board); + + for(auto it: state->commands) { + send_command(board, it.data(), it.size()); + } + + uint8_t end_cmd[2] = {MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::END)}; + send_command(board, end_cmd, sizeof(end_cmd)); + + state->commands_recorded(state->commands_recorded_context, board, response[2]); + + return MBL_MW_STATUS_OK; +} + +static int32_t macro_add_cmd_response_raw(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state = GET_MACRO_STATE(board); + state->commands_recorded(state->commands_recorded_context, board, response[2]); + + return MBL_MW_STATUS_OK; +} + +void init_macro_module(MblMwMetaWearBoard *board) { + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::BEGIN)), + forward_as_tuple(macro_add_cmd_response)); + + if (!board->macro_state) { + board->macro_state = make_shared(); + } +} + +void free_macro_module(void *state) { + delete (MacroState*) state; +} + +void mbl_mw_macro_record(MblMwMetaWearBoard *board, uint8_t exec_on_boot) { + auto state = GET_MACRO_STATE(board); + state->commands.clear(); + state->is_recording = true; + state->exec_on_boot = exec_on_boot == 0 ? 0 : 1; +} + +void mbl_mw_macro_record_raw(MblMwMetaWearBoard *board, uint8_t exec_on_boot, void *context, MblMwFnBoardPtrInt ready) { + auto state = GET_MACRO_STATE(board); + board->responses[MACRO_BEGIN] = macro_add_cmd_response_raw; + state->commands_recorded_context = context; + state->commands_recorded = ready; + + uint8_t command[3]= {MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::BEGIN), exec_on_boot}; + send_command(board, command, sizeof(command)); +} + +void mbl_mw_macro_end_record(MblMwMetaWearBoard *board, void *context, MblMwFnBoardPtrInt commands_recorded) { + auto state = GET_MACRO_STATE(board); + state->is_recording = false; + state->commands_recorded_context = context; + state->commands_recorded = commands_recorded; + + ThreadPool::schedule([state, board](void) -> void { + uint8_t command[3]= {MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::BEGIN), state->exec_on_boot}; + send_command(board, command, sizeof(command)); + }, 2000); +} + +void mbl_mw_macro_execute(MblMwMetaWearBoard *board, uint8_t id) { + uint8_t command[3] = { MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::EXECUTE), id }; + send_command(board, command, sizeof(command)); +} + +void mbl_mw_macro_erase_all(MblMwMetaWearBoard *board) { + uint8_t command[2] = { MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::ERASE_ALL) }; + send_command(board, command, sizeof(command)); +} + +void record_macro(const MblMwMetaWearBoard *board, const uint8_t* command, uint8_t len) { + auto state = GET_MACRO_STATE(board); + if (state != nullptr && state->is_recording) { + if (len >= MW_CMD_MAX_LENGTH) { + vector macro_cmd = { MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::ADD_PARTIAL) }; + macro_cmd.insert(macro_cmd.end(), command, command + PARTIAL_LENGTH); + state->commands.push_back(macro_cmd); + + macro_cmd = { MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::ADD_COMMAND) }; + macro_cmd.insert(macro_cmd.end(), command + PARTIAL_LENGTH, command + (len - PARTIAL_LENGTH)); + state->commands.push_back(macro_cmd); + } else { + vector macro_cmd = { MBL_MW_MODULE_MACRO, ORDINAL(MacroRegister::ADD_COMMAND) }; + macro_cmd.insert(macro_cmd.end(), command, command + len); + + state->commands.push_back(macro_cmd); + } + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro_private.h new file mode 100644 index 0000000..d482449 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro_private.h @@ -0,0 +1,5 @@ +#pragma once + +void init_macro_module(MblMwMetaWearBoard *board); +void free_macro_module(void *state); +void record_macro(const MblMwMetaWearBoard *board, const uint8_t* command, uint8_t len); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro_register.h new file mode 100644 index 0000000..9ebc99e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro_register.h @@ -0,0 +1,10 @@ +#pragma once + +enum class MacroRegister : uint8_t { + BEGIN = 2, + ADD_COMMAND, + END, + EXECUTE, + ERASE_ALL = 8, + ADD_PARTIAL +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/metawearboard_def.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/metawearboard_def.h new file mode 100644 index 0000000..e3799e7 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/metawearboard_def.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include + +#include "moduleinfo.h" +#include "responseheader.h" +#include "version.h" + +#include "metawear/core/datasignal_fwd.h" +#include "metawear/core/event_fwd.h" +#include "metawear/core/metawearboard_fwd.h" +#include "metawear/core/timer_fwd.h" +#include "metawear/dfu/cpp/dfu_operations.h" +#include "metawear/platform/btle_connection.h" +#include "metawear/platform/cpp/task.h" + +#define SEND_COMMAND send_command(board, command, sizeof(command)) +#define SEND_COMMAND_BOARD(board) send_command(board, command, sizeof(command)) + +enum class SerializationFormat : uint8_t { + INIT = 0, + SIGNAL_COMPONENT, + TIME_REFERENCE +}; + +typedef int32_t (*ResponseHandler)(MblMwMetaWearBoard *board, const uint8_t*, uint8_t); +/** UUIDs for the MetaWear DFU characteristic */ +const MblMwGattChar DFU_PACKET_CHAR = { 0x000015301212EFDE, 0x1523785FEABCD123, 0x000015321212EFDE, 0x1523785FEABCD123 }; +const MblMwGattChar DFU_CONTROL_POINT_CHAR = { 0x000015301212EFDE, 0x1523785FEABCD123, 0x000015311212EFDE, 0x1523785FEABCD123 }; + +struct MblMwMetaWearBoard { + MblMwMetaWearBoard(); + ~MblMwMetaWearBoard(); + + std::unordered_map module_events; + std::unordered_map responses; + std::unordered_map module_info; + std::unordered_map module_config; + + std::shared_ptr logger_state, timer_state, event_state, dp_state, macro_state, debug_state; + MblMwFnBoardPtrInt initialized; + void *initialized_context; + MblMwFnAnonSignalArray anon_signals_created; + void *anon_signals_context; + std::shared_ptr initialized_timeout; + MblMwBtleConnection btle_conn; + Version firmware_revision; + std::string module_number, hardware_revision, serial_number, manufacturer; + std::unique_ptr operations; + const char* filename; + + int64_t time_per_response; + int8_t module_discovery_index, dev_info_index; + + inline void write_gatt_char(const MblMwGattChar* gatt_char, MblMwGattCharWriteType type, const uint8_t* value, uint8_t len) const { + btle_conn.write_gatt_char(btle_conn.context, this, type, gatt_char, value, len); + } +}; + +void send_command(const MblMwMetaWearBoard* board, const uint8_t* command, uint8_t len); + +/** only for acc, gyro, and mag streaming */ +int32_t response_handler_packed_data(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len); +int32_t response_handler_data_no_id(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len); +int32_t response_handler_data_with_id(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/metawearboard_macro.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/metawearboard_macro.h new file mode 100644 index 0000000..0b32817 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/metawearboard_macro.h @@ -0,0 +1,16 @@ +#pragma once + +#define GET_EVENT(header) return board->module_events.count(header) ? board->module_events.at(header) : nullptr +#define GET_DATA_SIGNAL(header) GET_DATA_SIGNAL_BOARD(board, header) +#define GET_DATA_SIGNAL_BOARD(board, header) return board->module_events.count(header) ? dynamic_cast(board->module_events.at(header)) : nullptr + +#define SERIALIZE_MODULE_CONFIG(config_type, module) auto config = (config_type*)board->module_config.at(module);\ +state.insert(state.end(), (uint8_t*)config, ((uint8_t*)config) + sizeof(config_type)) + +#define DESERIALIZE_MODULE_CONFIG(config_type, module) if (board->module_config.count(module)) {\ + free(board->module_config.at(module));\ +}\ +void* config = malloc(sizeof(config_type));\ +memcpy(config, *state_stream, sizeof(config_type));\ +board->module_config[module] = config;\ +*state_stream += sizeof(config_type) diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.cpp new file mode 100644 index 0000000..e64f6db --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.cpp @@ -0,0 +1,46 @@ +#include "moduleinfo.h" +#include "register.h" + +ModuleInfo::ModuleInfo(const uint8_t *response, uint8_t size) : id(response[0]), present(size > 2) { + if (present) { + implementation = response[2]; + revision = response[3]; + } else { + implementation= 0xff; + revision= 0xff; + } + + if (size > 4) { + extra.assign(response + 4, response + size); + } +} + +ModuleInfo::ModuleInfo(uint8_t** state_stream) { + id = **state_stream; + implementation = *(++(*state_stream)); + revision = *(++(*state_stream)); + present = implementation != 0xff && revision != 0xff; + + if (present) { + uint8_t extra_size = *(++(*state_stream)); + ++(*state_stream); + if (extra_size) { + extra.assign(*state_stream, *state_stream + extra_size); + *state_stream += extra_size; + } + } else { + ++(*state_stream); + } + +} + +void ModuleInfo::serialize(std::vector& state) const { + state.push_back(id); + state.push_back(implementation); + state.push_back(revision); + + if (present) { + state.push_back((uint8_t)extra.size()); + state.insert(state.end(), extra.begin(), extra.end()); + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.h new file mode 100644 index 0000000..8d21a97 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +struct ModuleInfo { + uint8_t id; + bool present; + + std::vector extra; + uint8_t implementation; + uint8_t revision; + + ModuleInfo(const uint8_t *response, uint8_t size); + ModuleInfo(uint8_t** state_stream); + + void serialize(std::vector& state) const; +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/register.h new file mode 100644 index 0000000..ab8a41b --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/register.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#define ORDINAL(x) static_cast(x) +#define READ_REGISTER(x) (0x80 | x) +#define CLEAR_READ(x) (0x3f & x) \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.cpp new file mode 100644 index 0000000..2043e0b --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.cpp @@ -0,0 +1,70 @@ +#include "responseheader.h" + +const uint8_t READ_MASK= 0x80, SILENT_MASK = 0x40, NO_DATA_ID = 0xff; +#define COMPARE(param) (param > other.param ? 1 : (param == other.param ? 0 : -1)) + +ResponseHeader::ResponseHeader(uint8_t** state_stream) { + module_id = **state_stream; + register_id = *(++(*state_stream)); + data_id = *(++(*state_stream)); + (*state_stream)++; +} + +ResponseHeader::ResponseHeader(uint8_t module_id, uint8_t register_id) : + ResponseHeader(module_id, register_id, NO_DATA_ID) { } + +ResponseHeader::ResponseHeader(uint8_t module_id, uint8_t register_id, uint8_t data_id) : + module_id(module_id), register_id(register_id), data_id(data_id) { } + +ResponseHeader::ResponseHeader(const ResponseHeader &original) : + module_id(original.module_id), register_id(original.register_id), data_id(original.data_id) { } + +void ResponseHeader::disable_silent() { + register_id &= ~SILENT_MASK; +} + +void ResponseHeader::enable_silent() { + register_id |= SILENT_MASK; +} + +void ResponseHeader::mark_readable() { + register_id |= READ_MASK; +} + +void ResponseHeader::mark_unreadable(){ + register_id &= ~READ_MASK; +} + +bool ResponseHeader::is_readable() const { + return (READ_MASK & register_id) == READ_MASK; +} + +bool ResponseHeader::has_data_id() const { + return data_id == NO_DATA_ID; +} + +bool ResponseHeader::operator < (const ResponseHeader& other) const { + return COMPARE(module_id) * 4 + COMPARE(register_id) * 2 + COMPARE(data_id) < 0; +} + +bool ResponseHeader::operator ==(const ResponseHeader& other) const { + return module_id == other.module_id && register_id == other.register_id && data_id == other.data_id; +} + +void ResponseHeader::serialize(std::vector& state) const { + state.push_back(module_id); + state.push_back(register_id); + state.push_back(data_id); +} + +namespace std { + +size_t hash::operator()(const ResponseHeader& key) const { + ///< Generated by IntelliJ + size_t result = (size_t) key.module_id; + result = 31 * result + (size_t) key.register_id; + result = 31 * result + (size_t) key.data_id; + return result; +} + +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.h new file mode 100644 index 0000000..4bea284 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +struct ResponseHeader { + uint8_t module_id, register_id, data_id; + + ResponseHeader(uint8_t** state_stream); + ResponseHeader(uint8_t module_id, uint8_t register_id); + ResponseHeader(uint8_t module_id, uint8_t register_id, uint8_t data_id); + ResponseHeader(const ResponseHeader &original); + + void disable_silent(); + void enable_silent(); + void mark_readable(); + void mark_unreadable(); + + bool is_readable() const; + bool has_data_id() const; + void serialize(std::vector& state) const; + + bool operator <(const ResponseHeader& other) const; + bool operator ==(const ResponseHeader& other) const; +}; + +namespace std { + +template <> +struct hash { + size_t operator()(const ResponseHeader& key) const; +}; + +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings.cpp new file mode 100644 index 0000000..42311fd --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings.cpp @@ -0,0 +1,282 @@ +#include "metawear/core/module.h" + +#include "metawear/core/settings.h" +#include "settings_private.h" + +#include "constant.h" +#include "datasignal_private.h" +#include "event_private.h" +#include "metawearboard_def.h" +#include "metawearboard_macro.h" +#include "register.h" +#include "responseheader.h" +#include "settings_register.h" + +#include +#include +#include + +using std::memcpy; +using std::stringstream; +using std::vector; +using std::forward_as_tuple; +using std::piecewise_construct; +using std::unordered_map; + +const float AD_INTERVAL_STEP= 0.625f, CONN_INTERVAL_STEP= 1.25f, TIMEOUT_STEP= 10; +const uint8_t CONN_PARAMS_REVISION= 1, DISCONNECTED_EVENT_REVISION= 2, BATTERY_REVISION= 3, CHARGE_STATUS_REVISION = 5, WHITELIST_REVISION = 6, MMS_REVISION = 9; + +const ResponseHeader + SETTINGS_BATTERY_STATE_RESPONSE_HEADER(MBL_MW_MODULE_SETTINGS, READ_REGISTER(ORDINAL(SettingsRegister::BATTERY_STATE))), + SETTINGS_DISCONNECT_EVENT_RESPONSE_HEADER(MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::DISCONNECT_EVENT)), + SETTINGS_MAC_RESPONSE_HEADER(MBL_MW_MODULE_SETTINGS, READ_REGISTER(ORDINAL(SettingsRegister::MAC))), + POWER_STATUS_RESPONSE_HEADER(MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::POWER_STATUS)), + CHARGE_STATUS_RESPONSE_HEADER(MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::CHARGE_STATUS)); + +struct SettingsTransientState { + void *read_power_status_context, *read_charge_status_context; + MblMwFnBoardPtrInt read_power_status_handler, read_charge_status_handler; +}; + +static unordered_map transient_states; + + +static int32_t current_power_status_received(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + transient_states[board].read_power_status_handler(transient_states[board].read_power_status_context, board, response[2]); + return 0; +} + +static int32_t current_charge_status_received(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + transient_states[board].read_charge_status_handler(transient_states[board].read_charge_status_context, board, response[2]); + return 0; +} + +void init_settings_module(MblMwMetaWearBoard *board) { + auto info = &board->module_info.at(MBL_MW_MODULE_SETTINGS); + + if (info->revision >= BATTERY_REVISION) { + MblMwDataSignal* battery; + if (board->module_events.count(SETTINGS_BATTERY_STATE_RESPONSE_HEADER)) { + battery = dynamic_cast(board->module_events[SETTINGS_BATTERY_STATE_RESPONSE_HEADER]); + } else { + battery = new MblMwDataSignal(SETTINGS_BATTERY_STATE_RESPONSE_HEADER, board, DataInterpreter::SETTINGS_BATTERY_STATE, 1, 3, 0, 0); + board->module_events[SETTINGS_BATTERY_STATE_RESPONSE_HEADER] = battery; + } + if (!battery->components.size()) { + // MBL_MW_MODULE_SETTINGS_BATT_VOLTAGE_INDEX + battery->components.push_back(new MblMwDataSignal(SETTINGS_BATTERY_STATE_RESPONSE_HEADER, board, DataInterpreter::UINT32, 1, 2, 0, 1)); + // MBL_MW_MODULE_SETTINGS_BATT_CHARGE_INDEX + battery->components.push_back(new MblMwDataSignal(SETTINGS_BATTERY_STATE_RESPONSE_HEADER, board, DataInterpreter::UINT32, 1, 1, 0, 0)); + } + board->responses[SETTINGS_BATTERY_STATE_RESPONSE_HEADER] = response_handler_data_no_id; + } + if (info->revision >= DISCONNECTED_EVENT_REVISION) { + if (!board->module_events.count(SETTINGS_DISCONNECT_EVENT_RESPONSE_HEADER)) { + board->module_events[SETTINGS_DISCONNECT_EVENT_RESPONSE_HEADER] = new MblMwEvent(SETTINGS_DISCONNECT_EVENT_RESPONSE_HEADER, board); + } + if (!board->module_events.count(SETTINGS_MAC_RESPONSE_HEADER)) { + board->module_events[SETTINGS_MAC_RESPONSE_HEADER] = new MblMwDataSignal(SETTINGS_MAC_RESPONSE_HEADER, board, + DataInterpreter::MAC_ADDRESS, FirmwareConverter::DEFAULT, 1, 6, 0, 0); + } + board->responses[SETTINGS_MAC_RESPONSE_HEADER]= response_handler_data_no_id; + } + if (info->revision >= CHARGE_STATUS_REVISION && info->extra.size() > 0 && (info->extra[0] & 0x1) == 0x1) { + if (!board->module_events.count(POWER_STATUS_RESPONSE_HEADER)) { + board->module_events[POWER_STATUS_RESPONSE_HEADER] = new MblMwDataSignal(POWER_STATUS_RESPONSE_HEADER, board, + DataInterpreter::UINT32, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + + auto readable_power_status(POWER_STATUS_RESPONSE_HEADER); + readable_power_status.mark_readable(); + board->responses[readable_power_status]= current_power_status_received; + board->responses[POWER_STATUS_RESPONSE_HEADER]= response_handler_data_no_id; + } + + if (info->revision >= CHARGE_STATUS_REVISION && info->extra.size() > 0 && (info->extra[0] & 0x2) == 0x2) { + if (!board->module_events.count(CHARGE_STATUS_RESPONSE_HEADER)) { + board->module_events[CHARGE_STATUS_RESPONSE_HEADER] = new MblMwDataSignal(CHARGE_STATUS_RESPONSE_HEADER, board, + DataInterpreter::UINT32, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + + auto readable_charge_status(CHARGE_STATUS_RESPONSE_HEADER); + readable_charge_status.mark_readable(); + board->responses[readable_charge_status]= current_charge_status_received; + board->responses[CHARGE_STATUS_RESPONSE_HEADER]= response_handler_data_no_id; + } + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_SETTINGS, READ_REGISTER(ORDINAL(SettingsRegister::WHITELIST_ADDRESSES))), + forward_as_tuple(response_handler_data_with_id)); + + SettingsTransientState newState = {nullptr, nullptr, nullptr, nullptr}; + transient_states.insert({board, newState}); +} + +void free_settings_module(MblMwMetaWearBoard* board) { + transient_states.erase(board); +} + +MblMwEvent* mbl_mw_settings_get_disconnect_event(const MblMwMetaWearBoard *board) { + GET_EVENT(SETTINGS_DISCONNECT_EVENT_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_settings_get_battery_state_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(SETTINGS_BATTERY_STATE_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_settings_get_mac_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(SETTINGS_MAC_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_settings_get_power_status_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(POWER_STATUS_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_settings_get_charge_status_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(CHARGE_STATUS_RESPONSE_HEADER); +} + +void mbl_mw_settings_read_current_power_status(MblMwMetaWearBoard* board, void* context, MblMwFnBoardPtrInt handler) { + if (board->module_events.count(POWER_STATUS_RESPONSE_HEADER)) { + transient_states[board].read_power_status_handler = handler; + transient_states[board].read_power_status_context = context; + + uint8_t command[2]= {MBL_MW_MODULE_SETTINGS, READ_REGISTER(ORDINAL(SettingsRegister::POWER_STATUS))}; + SEND_COMMAND; + } else { + handler(context, board, MBL_MW_SETTINGS_POWER_STATUS_UNSUPPORTED); + } +} + +void mbl_mw_settings_read_current_charge_status(MblMwMetaWearBoard* board, void* context, MblMwFnBoardPtrInt handler) { + if (board->module_events.count(CHARGE_STATUS_RESPONSE_HEADER)) { + transient_states[board].read_charge_status_handler = handler; + transient_states[board].read_charge_status_context = context; + + uint8_t command[2]= {MBL_MW_MODULE_SETTINGS, READ_REGISTER(ORDINAL(SettingsRegister::CHARGE_STATUS))}; + SEND_COMMAND; + } else { + handler(context, board, MBL_MW_SETTINGS_CHARGE_STATUS_UNSUPPORTED); + } +} + +void mbl_mw_settings_set_device_name(const MblMwMetaWearBoard *board, const uint8_t *device_name, uint8_t len) { + vector command(device_name, device_name + len); + command.insert(command.begin(), {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::DEVICE_NAME)}); + send_command(board, command.data(), (uint8_t) command.size()); +} + +void mbl_mw_settings_set_ad_interval(const MblMwMetaWearBoard *board, uint16_t interval, uint8_t timeout) { + mbl_mw_settings_set_ad_parameters(board, interval, timeout, MBL_MW_BLE_AD_TYPE_CONNECTED_UNDIRECTED); +} + +void mbl_mw_settings_set_ad_parameters(const MblMwMetaWearBoard *board, uint16_t interval, uint8_t timeout, MblMwBleAdType type) { + vector command = {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::AD_INTERVAL), 0, 0, timeout}; + + if (board->module_info.at(MBL_MW_MODULE_SETTINGS).revision >= CONN_PARAMS_REVISION) { + interval/= AD_INTERVAL_STEP; + } + memcpy(command.data() + 2, &interval, sizeof(interval)); + + if (board->module_info.at(MBL_MW_MODULE_SETTINGS).revision >= WHITELIST_REVISION) { + command.push_back(static_cast(type)); + } + + send_command(board, command.data(), (uint8_t) command.size()); +} + +void mbl_mw_settings_set_tx_power(const MblMwMetaWearBoard *board, int8_t tx_power) { + uint8_t command[3]= {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::TX_POWER), static_cast(tx_power)}; + SEND_COMMAND; +} + +void mbl_mw_settings_start_advertising(const MblMwMetaWearBoard *board) { + uint8_t command[2]= {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::START_ADVERTISING)}; + SEND_COMMAND; +} + +void mbl_mw_settings_set_scan_response(const MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + if (len > MW_CMD_MAX_LENGTH) { + vector first(response, response + 13), second(response + 13, response + len); + + first.insert(first.begin(), {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::PARTIAL_SCAN_RESPONSE)}); + second.insert(second.begin(), {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::SCAN_RESPONSE)}); + + send_command(board, first.data(), (uint8_t) first.size()); + send_command(board, second.data(), (uint8_t) second.size()); + } else { + vector command(response, response + len); + + command.insert(command.begin(), {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::SCAN_RESPONSE)}); + send_command(board, command.data(), (uint8_t) command.size()); + } +} + +void mbl_mw_settings_set_connection_parameters(const MblMwMetaWearBoard *board, float min_conn_interval, float max_conn_interval, uint16_t latency, + uint16_t timeout) { + uint8_t command[10]= {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::CONNECTION_PARAMS)}; + uint16_t parameters[4]= {static_cast(min_conn_interval / CONN_INTERVAL_STEP), + static_cast(max_conn_interval / CONN_INTERVAL_STEP), latency, static_cast(timeout / TIMEOUT_STEP)}; + + memcpy(command + 2, parameters, sizeof(parameters)); + SEND_COMMAND; +} + +void mbl_mw_settings_add_whitelist_address(const MblMwMetaWearBoard *board, uint8_t index, const MblMwBtleAddress *address) { + if (board->module_info.at(MBL_MW_MODULE_SETTINGS).revision >= WHITELIST_REVISION) { + uint8_t command[10]= {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::WHITELIST_ADDRESSES), index}; + memcpy(command + 3, address, sizeof(MblMwBtleAddress)); + SEND_COMMAND; + } +} + +MblMwDataSignal* mbl_mw_settings_get_whitelist_data_signal(MblMwMetaWearBoard* board, uint8_t index) { + ResponseHeader header(MBL_MW_MODULE_SETTINGS, READ_REGISTER(ORDINAL(SettingsRegister::WHITELIST_ADDRESSES)), index); + if (!board->module_events.count(header)) { + board->module_events[header]= new MblMwDataSignal(header, board, DataInterpreter::BTLE_ADDRESS, 1, 7, 0, 0); + } + return dynamic_cast(board->module_events.at(header)); +} + +void mbl_mw_settings_set_whitelist_filter_mode(const MblMwMetaWearBoard *board, MblMwWhitelistFilter mode) { + if (board->module_info.at(MBL_MW_MODULE_SETTINGS).revision >= WHITELIST_REVISION) { + uint8_t command[3]= {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::WHITELIST_FILTER_MODE), static_cast(mode)}; + SEND_COMMAND; + } +} + +void mbl_mw_settings_enable_3V_regulator(const MblMwMetaWearBoard *board, uint8_t enable) { + if (board->module_info.at(MBL_MW_MODULE_SETTINGS).revision >= MMS_REVISION) { + uint8_t command[3]= {MBL_MW_MODULE_SETTINGS, ORDINAL(SettingsRegister::THREE_VOLT_POWER), static_cast(enable)}; + SEND_COMMAND; + } +} + +void create_settings_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(SettingsRegister::BATTERY_STATE): + uri << "battery"; + switch(signal->length()) { + case 1: + uri << "[0]"; + break; + case 2: + uri << "[1]"; + break; + } + break; + case ORDINAL(SettingsRegister::POWER_STATUS): + uri << "power-status"; + break; + case ORDINAL(SettingsRegister::CHARGE_STATUS): + uri << "charge-status"; + break; + } +} + +uint8_t mbl_mw_settings_get_firmware_build_id(const MblMwMetaWearBoard *board) { + auto info = &board->module_info.at(MBL_MW_MODULE_SETTINGS); + if (info->extra.size() > 1) { + return info->extra[1]; + } + return 0; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings_private.h new file mode 100644 index 0000000..f7be86d --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings_private.h @@ -0,0 +1,8 @@ +#pragma once + +#include "metawear/core/metawearboard_fwd.h" +#include + +void init_settings_module(MblMwMetaWearBoard *board); +void free_settings_module(MblMwMetaWearBoard* board); +void create_settings_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings_register.h new file mode 100644 index 0000000..f7ce073 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings_register.h @@ -0,0 +1,19 @@ +#pragma once + +enum class SettingsRegister : uint8_t { + DEVICE_NAME = 1, + AD_INTERVAL, + TX_POWER, + START_ADVERTISING = 5, + SCAN_RESPONSE = 7, + PARTIAL_SCAN_RESPONSE, + CONNECTION_PARAMS, + DISCONNECT_EVENT, + MAC = 0xb, + BATTERY_STATE = 0xc, + POWER_STATUS = 0x11, + CHARGE_STATUS, + WHITELIST_FILTER_MODE, + WHITELIST_ADDRESSES, + THREE_VOLT_POWER = 0x1c +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer.cpp new file mode 100644 index 0000000..e76dc09 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer.cpp @@ -0,0 +1,129 @@ +#include "metawear/core/event.h" +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/core/timer.h" +#include "metawear/platform/cpp/async_creator.h" +#include "metawear/platform/cpp/threadpool.h" + +#include "metawearboard_def.h" +#include "timer_private.h" +#include "timer_register.h" + +#include + +using std::forward_as_tuple; +using std::make_shared; +using std::memcpy; +using std::piecewise_construct; +using std::static_pointer_cast; + +#define GET_TIMER_STATE(board) static_pointer_cast(board->timer_state) + +const uint16_t REPEAT_INDEFINITELY= 0xffff; + +struct TimerState : public AsyncCreator { + MblMwFnTimerPtr timer_callback; + void *timer_context; +}; + +static int32_t timer_created(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state = GET_TIMER_STATE(board); + + state->timeout->cancel(); + + MblMwTimer *new_timer = new MblMwTimer(ResponseHeader(MBL_MW_MODULE_TIMER, ORDINAL(TimerRegister::NOTIFY), response[2]), board); + board->module_events.emplace(new_timer->header, new_timer); + + state->timer_callback(state->timer_context, new_timer); + state->create_next(true); + + return MBL_MW_STATUS_OK; +} + + +MblMwTimer::MblMwTimer(uint8_t** state_stream, MblMwMetaWearBoard *owner) : MblMwEvent(state_stream, owner) { +} + +MblMwTimer::MblMwTimer(const ResponseHeader& header, MblMwMetaWearBoard *owner) : MblMwEvent(header, owner) { +} + +MblMwTimer::~MblMwTimer() { + if (remove) { + remove_from_board(); + } +} + +void MblMwTimer::remove_from_board() { + uint8_t command[3] = { MBL_MW_MODULE_TIMER, ORDINAL(TimerRegister::REMOVE), header.data_id }; + SEND_COMMAND_BOARD(owner); +} + +void init_timer_module(MblMwMetaWearBoard *board) { + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_TIMER, ORDINAL(TimerRegister::TIMER_ENTRY)), + forward_as_tuple(timer_created)); + + if (!board->timer_state) { + board->timer_state= make_shared(); + } +} + +void free_timer_module(void *state) { + delete (TimerState*) state; +} + +void disconnect_timer(MblMwMetaWearBoard* board) { + auto state = GET_TIMER_STATE(board); + if (state != nullptr) { + state->pending_fns.clear(); + } +} + +void mbl_mw_timer_create(MblMwMetaWearBoard *board, uint32_t period, uint16_t repetitions, uint8_t delay, void *context, MblMwFnTimerPtr received_timer) { + auto state = GET_TIMER_STATE(board); + + state->pending_fns.push([=](void) -> void { + uint8_t command[9]= {MBL_MW_MODULE_TIMER, ORDINAL(TimerRegister::TIMER_ENTRY)}; + memcpy(command + 2, &period, sizeof(period)); + memcpy(command + 6, &repetitions, sizeof(repetitions)); + command[8]= (delay != 0) ? 0 : 1; + + state->timer_callback= received_timer; + state->timer_context= context; + state->timeout= ThreadPool::schedule([context, state, received_timer](void) -> void { + received_timer(context, nullptr); + state->create_next(true); + }, board->time_per_response); + + SEND_COMMAND; + }); + state->create_next(false); +} + +void mbl_mw_timer_create_indefinite(MblMwMetaWearBoard *board, uint32_t period, uint8_t delay, void *context, MblMwFnTimerPtr received_timer) { + return mbl_mw_timer_create(board, period, REPEAT_INDEFINITELY, delay, context, received_timer); +} + + +uint8_t mbl_mw_timer_get_id(const MblMwTimer* timer) { + return timer->header.data_id; +} + +MblMwTimer* mbl_mw_timer_lookup_id(const MblMwMetaWearBoard* board, uint8_t id) { + ResponseHeader map_key(MBL_MW_MODULE_TIMER, ORDINAL(TimerRegister::NOTIFY), id); + return board->module_events.count(map_key) ? dynamic_cast(board->module_events.at(map_key)) : nullptr; +} + +void mbl_mw_timer_start(const MblMwTimer* timer) { + uint8_t command[3]= {MBL_MW_MODULE_TIMER, ORDINAL(TimerRegister::START), timer->header.data_id}; + SEND_COMMAND_BOARD(timer->owner); +} + +void mbl_mw_timer_stop(const MblMwTimer* timer) { + uint8_t command[3]= {MBL_MW_MODULE_TIMER, ORDINAL(TimerRegister::STOP), timer->header.data_id}; + SEND_COMMAND_BOARD(timer->owner); +} + +void mbl_mw_timer_remove(MblMwTimer* timer) { + timer->owner->module_events.erase(timer->header); + delete timer; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer_private.h new file mode 100644 index 0000000..27ac73c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer_private.h @@ -0,0 +1,16 @@ +#pragma once + +#include "metawear/core/timer_fwd.h" +#include "event_private.h" + +struct MblMwTimer : public MblMwEvent { + MblMwTimer(uint8_t** state_stream, MblMwMetaWearBoard *owner); + MblMwTimer(const ResponseHeader& header, MblMwMetaWearBoard *owner); + virtual ~MblMwTimer(); + + void remove_from_board(); +}; + +void init_timer_module(MblMwMetaWearBoard *board); +void free_timer_module(void *state); +void disconnect_timer(MblMwMetaWearBoard* board); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer_register.h new file mode 100644 index 0000000..76048a0 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer_register.h @@ -0,0 +1,13 @@ +#pragma once + +#include "register.h" + +enum class TimerRegister : uint8_t { + ENABLE = 1, + TIMER_ENTRY, + START, + STOP, + REMOVE, + NOTIFY, + NOTIFY_ENABLE +}; \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.cpp new file mode 100644 index 0000000..fd065e2 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.cpp @@ -0,0 +1,100 @@ +#include "version.h" + +#include +#include +#include +#include +#include + +using std::atoi; +using std::length_error; +using std::string; +using std::stringstream; +using std::vector; + +const uint8_t EMPTY_VALUE= 0; +const char SEPARATOR= '.'; + +Version::Version() : Version(EMPTY_VALUE, EMPTY_VALUE, EMPTY_VALUE) { +} + +Version::Version(const string& version) { + assign(version); +} + +Version::Version(uint8_t major, uint8_t minor, uint8_t step) { + uint8_t state[3] = { step, minor, major }, *ptr = state; + deserialize(&ptr); +} + +void Version::deserialize(uint8_t** state_stream) { + step = **state_stream; + minor = *(++(*state_stream)); + major = *(++(*state_stream)); + ++(*state_stream); + + stringstream buffer; + buffer << (int) major << SEPARATOR << (int) minor << SEPARATOR << (int) step; + sem_ver = buffer.str(); +} + +void Version::serialize(vector& state) const { + state.push_back(step); + state.push_back(minor); + state.push_back(major); +} + +bool Version::empty() const { + return major == EMPTY_VALUE && minor == EMPTY_VALUE && step == EMPTY_VALUE; +} + +void Version::assign(const std::string& new_version) { + sem_ver.assign(new_version); + string tempStr; + vector parts; + size_t i= 0; + + while(i < new_version.size()) { + if (new_version[i] == SEPARATOR && !tempStr.empty()) { + parts.push_back(tempStr); + tempStr.clear(); + } else { + tempStr+= new_version[i]; + } + i++; + } + if (!tempStr.empty()) { + parts.push_back(tempStr); + } + + if (parts.size() != 3) { + throw length_error("version string \'" + new_version + "\' did not split into 3 elements"); + } + major = atoi(parts.at(0).c_str()); + minor = atoi(parts.at(1).c_str()); + step = atoi(parts.at(2).c_str()); +} + +Version& Version::operator =(const Version& original) { + if (this != &original) { + major= original.major; + minor= original.minor; + step= original.step; + sem_ver = original.sem_ver; + } + return *this; +} + +bool operator <(const Version& left, const Version& right) { + auto compare = [](uint8_t l, uint8_t r) -> int8_t { + if (l < r) return -1; + if (l > r) return 1; + return 0; + }; + + return compare(left.major, right.major) * 4 + compare(left.minor, right.minor) * 2 + compare(left.step, right.step) < 0; +} + +bool operator ==(const Version& left, const Version& right) { + return left.major == right.major && left.minor == right.minor && left.step == right.step; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.h new file mode 100644 index 0000000..d71dfbd --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include + +struct Version { + Version(); + Version(const std::string& version); + Version(uint8_t major, uint8_t minor, uint8_t step); + + void deserialize(uint8_t** state_stream); + void serialize(std::vector& state) const; + + bool empty() const; + void assign(const std::string& new_version); + Version& operator =(const Version& original); + + std::string sem_ver; + uint8_t major, minor, step; +}; + +bool operator <(const Version& left, const Version& right); +bool operator ==(const Version& left, const Version& right); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/data.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/data.h new file mode 100644 index 0000000..426bfaf --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/data.h @@ -0,0 +1,52 @@ +/** + * @copyright MbientLab License + * @file data.h + * @brief Functions and types for data received from an MblMwDataSignal + */ +#pragma once + +#include + +/** + * Enumeration of sensor data types + */ +typedef enum { + MBL_MW_DT_ID_UINT32= 0, ///< Data is an unsigned integer + MBL_MW_DT_ID_FLOAT, ///< Data is a float + MBL_MW_DT_ID_CARTESIAN_FLOAT, ///< Data is a CartesianFloat + MBL_MW_DT_ID_INT32, ///< Data is a signed integer + MBL_MW_DT_ID_BYTE_ARRAY, ///< Data is a byte array + MBL_MW_DT_ID_BATTERY_STATE, ///< Data is a BatteryState + MBL_MW_DT_ID_TCS34725_ADC, ///< Data is a Tcs34725ColorAdc + MBL_MW_DT_ID_EULER_ANGLE, + MBL_MW_DT_ID_QUATERNION, + MBL_MW_DT_ID_CORRECTED_CARTESIAN_FLOAT, + MBL_MW_DT_ID_OVERFLOW_STATE, + MBL_MW_DT_ID_SENSOR_ORIENTATION, + MBL_MW_DT_ID_STRING, + MBL_MW_DT_ID_LOGGING_TIME, + MBL_MW_DT_ID_BTLE_ADDRESS, + MBL_MW_DT_ID_BOSCH_ANY_MOTION, + MBL_MW_DT_ID_CALIBRATION_STATE, + MBL_MW_DT_ID_DATA_ARRAY, + MBL_MW_DT_ID_BOSCH_TAP, + MBL_MW_DT_ID_BOSCH_GESTURE +} MblMwDataTypeId; + +/** + * Wrapper class encapsulating one sample of sensor data + */ +typedef struct { + int64_t epoch; ///< Number of milliseconds since epoch + void* extra; ///< Extra information attached to this data sample + void* value; ///< Pointer to the data value + MblMwDataTypeId type_id; ///< ID represnting the data type the value pointer points to + uint8_t length; ///< Size of the value +} MblMwData; + +/** + * Definition for callback functions that handle data from an MblMwDataSignal + * @param context Pointer to the context the enclosing function was called with + * @param data Data returned from the signal + */ +typedef void (*MblMwFnData)(void *context, const MblMwData* data); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/datasignal.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/datasignal.h new file mode 100644 index 0000000..4e767e9 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/datasignal.h @@ -0,0 +1,69 @@ +/** + * @copyright MbientLab License + * @file datasignal.h + * @brief Functions for controlling a MblMwDataSignal + */ +#pragma once + +#include "data.h" +#include "datasignal_fwd.h" +#include "logging_fwd.h" + +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Retrieves an individual value from a multi-valued datasignal i.e. MblMwCartesianFloat datasignal is 3 float values. + * For example, the x component for the acc x,y,z can be retrieved with this function + * These individual signals can use the full suite of + * @param signal Data signal to lookup + * @param index Index of the component to return + * @return Signal component, null if signal is signle valued + */ +METAWEAR_API MblMwDataSignal* mbl_mw_datasignal_get_component(const MblMwDataSignal* signal, uint8_t index); +/** + * Subscribes to a data stream, processing messages with the given handler + * @param signal Data signal to subscribe to + * @param context Pointer to additional data for the callback function + * @param received_data Callback function to handle data received from the signal + */ +METAWEAR_API void mbl_mw_datasignal_subscribe(MblMwDataSignal *signal, void *context, MblMwFnData received_data); +/** + * Unsubscribes from a data stream + * @param signal Data signal to unsubscribe from + */ +METAWEAR_API void mbl_mw_datasignal_unsubscribe(MblMwDataSignal *signal); +/** + * Check if the data signal can be explicitly read + * @param signal Data signal to check + * @return Zero if not readable, non-zero if it is + */ +METAWEAR_API int32_t mbl_mw_datasignal_is_readable(const MblMwDataSignal* signal); +/** + * Reads data from sensor represented by the data signal. + * Data is forwarded to the callback function assigned by the mbl_mw_datasignal_subscribe function + * @param signal Data signal to read from + */ +METAWEAR_API void mbl_mw_datasignal_read(const MblMwDataSignal* signal); +/** + * Reads data from sensor represented by the data signal. + * Data is forwarded to the callback function assigned by the mbl_mw_datasignal_subscribe function. + * This variant is for reads that require additional parameters. + * @param signal Data signal to read from + * @param parameters Additional parameters required for the read operation + */ +METAWEAR_API void mbl_mw_datasignal_read_with_parameters(const MblMwDataSignal* signal, const void* parameters); +/** + * Creates an MblMwDataLogger for the signal + * @param signal Data signal to log + * @param context Pointer to additional data for the callback function + * @param logger_ready Callback function to be executed when the logger is created + */ +METAWEAR_API void mbl_mw_datasignal_log(MblMwDataSignal *signal, void *context, MblMwFnDataLoggerPtr logger_ready); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/datasignal_fwd.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/datasignal_fwd.h new file mode 100644 index 0000000..88aaaed --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/datasignal_fwd.h @@ -0,0 +1,16 @@ +/** + * @copyright MbientLab License + * @file datasignal_fwd.h + * @brief Forward declaration for the MblMwDataSignal type + */ +#pragma once + +/** + * A event fired from the MetaWear board that also contains data. An MblMwDataSignal pointer can be casted as an + * MblMwEvent pointer and used with any function that accepts an MblMwEvent pointer. + */ +#ifdef __cplusplus +struct MblMwDataSignal; +#else +typedef struct MblMwDataSignal MblMwDataSignal; +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/debug.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/debug.h new file mode 100644 index 0000000..cd6af0d --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/debug.h @@ -0,0 +1,94 @@ +/** + * @copyright MbientLab License + * @file debug.h + * @brief Testing and debug functions, for advanced users only + */ +#pragma once + +#include + +#include "data.h" +#include "metawearboard_fwd.h" +#include "datasignal_fwd.h" +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Issues a soft reset + * @param board Calling object + */ +METAWEAR_API void mbl_mw_debug_reset(const MblMwMetaWearBoard *board); +/** + * Restarts the board in bootloader mode + * @param board Calling object + */ +METAWEAR_API void mbl_mw_debug_jump_to_bootloader(const MblMwMetaWearBoard *board); +/** + * Instructs the board to terminate the connection + * @param board Calling object + */ +METAWEAR_API void mbl_mw_debug_disconnect(const MblMwMetaWearBoard *board); +/** + * Restarts the board after performing garbage collection + * @param board Calling object + */ +METAWEAR_API void mbl_mw_debug_reset_after_gc(const MblMwMetaWearBoard *board); +/** + * Places the board in a powered down state after the next reset. When in power save mode, press the switch + * or plug in the USB charger to wake the board up. + * @param board Calling object + */ +METAWEAR_API void mbl_mw_debug_enable_power_save(const MblMwMetaWearBoard *board); +/** + * Enables/disables stack overflow assertion. Function will do nothing if feature is unsupported. + * @param board Calling object + * @param enable 0 to disable, non-zero value to enable + */ +METAWEAR_API void mbl_mw_debug_set_stack_overflow_assertion(const MblMwMetaWearBoard *board, uint8_t enable); +/** + * Reads the current stack state. If feature is unspported, nullptr will be passed to the `handler` parameter + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param handler Callback function for handling the received data + */ +METAWEAR_API void mbl_mw_debug_read_stack_overflow_state(const MblMwMetaWearBoard *board, void *context, MblMwFnData handler); +/** + * Reads the internal queues' current usage statistics; data is returned as a byte array. + * If feature is unspported, nullptr will be passed to the `handler` parameter + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param handler Callback function for handling the received data + */ +METAWEAR_API void mbl_mw_debug_read_schedule_queue_usage(const MblMwMetaWearBoard *board, void *context, MblMwFnData handler); +/** + * Creates a synthetic notification internally to the MetaWear system. Useful for testing. + * @param board Calling object + * @param value Value to spoof: [Module ID, Register ID, Notifcation En, Optional Index, Data...] + * @param lenght Size of the value array + */ +METAWEAR_API void mbl_mw_debug_spoof_notification(const MblMwMetaWearBoard *board, const uint8_t *value, uint8_t length); +/** + * Sends a raw command directly to the MetaWear. Useful for testing. + * @param board Calling object + * @param value Value to send: [Module ID, Register ID, Optional Index, Data...] + * @param lenght Size of the value array + */ +METAWEAR_API void mbl_mw_debug_send_command(const MblMwMetaWearBoard *board, const uint8_t *value, uint8_t length); +/** + * Retrieves a data signal representing the key register value. This is a simple + * 4 byte scratch register. + * @param board Board to receive data from + */ +METAWEAR_API MblMwDataSignal* mbl_mw_debug_get_key_register_data_signal(const MblMwMetaWearBoard *board); +/** + * Sets the key register value. This is a simple 4 byte scratch register. + * @param board Board to receive data from + */ +METAWEAR_API void mbl_mw_debug_set_key_register(const MblMwMetaWearBoard *board, uint32_t value); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/event.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/event.h new file mode 100644 index 0000000..d21c6f6 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/event.h @@ -0,0 +1,48 @@ +/** + * @copyright MbientLab License + * @file event.h + * @brief Functions for the MblMwEvent type + */ + +#pragma once + +#include "event_fwd.h" +#include "metawearboard_fwd.h" + +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Retrieves the MblMwMetaWearBoard the event belongs to + * @param event Event to lookup + * @return Pointer to the owner + */ +METAWEAR_API MblMwMetaWearBoard* mbl_mw_event_get_owner(const MblMwEvent *event); +/** + * Enables command recording. + * Commands can be used to execute functions on the sensor as a result of an event. + * For example, when the time counts to 30 (the event), take a temperature reading (the command). + * All MetaWear commands called after this point will be executed when the owning event is fired + * @param event Event to record commands for + */ +METAWEAR_API void mbl_mw_event_record_commands(MblMwEvent *event); +/** + * Ends command recording. + * This function is non-blocking and will asynchronously alert the caller when the operation is completed. + * @param event Event to end recording for + * @param context Pointer to additional data for the callback function + * @param commands_recorded Callback function to be executed when commands have been recorded + */ +METAWEAR_API void mbl_mw_event_end_record(MblMwEvent *event, void *context, MblMwFnEventPtrInt commands_recorded); +/** + * Remove all recorded events from the board. + * @param board Calling object + */ +METAWEAR_API void mbl_mw_event_remove_all(MblMwMetaWearBoard* board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/event_fwd.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/event_fwd.h new file mode 100644 index 0000000..cae68fc --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/event_fwd.h @@ -0,0 +1,25 @@ +/** + * @copyright MbientLab License + * @file event_fwd.h + * @brief Forward declaration of the MblMwEvent type + */ +#pragma once + +#include + +/** + * Represents an event fired from the MetaWear board. + */ +#ifdef __cplusplus +struct MblMwEvent; +#else +typedef struct MblMwEvent MblMwEvent; +#endif + +/** + * Definition for callback functions that accept an MblMwEvent pointer and an int32 + * @param context Pointer to the context the enclosing function was called with + * @param event Event to be used with the function + * @param status Status code passed into the function + */ +typedef void(*MblMwFnEventPtrInt)(void *context, MblMwEvent* event, int32_t status); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/logging.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/logging.h new file mode 100644 index 0000000..9ea2e62 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/logging.h @@ -0,0 +1,198 @@ +/** + * @copyright MbientLab License + * @file logging.h + * @brief Controls the onboard logging system + */ +#pragma once + +#include + +#include "data.h" +#include "datasignal_fwd.h" +#include "logging_fwd.h" +#include "metawearboard_fwd.h" + +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Callback functions for handling notifications from the logger + */ +typedef struct { + /** + * Pointer to additional data for the callback functions + */ + void *context; + /** + * Called when a progress update is received + * @param context Pointer to the context field + * @param entries_left Number of entries left to download + * @param total_entries Total number of entries + */ + void (*received_progress_update)(void *context, uint32_t entries_left, uint32_t total_entries); + /** + * Called when a log entry has been received but cannot be matched to a log handler + * @param context Pointer to the context field + * @param id Id of the received log entry + * @param epoch Number of milliseconds since epoch + * @param data Byte array holding the data + * @param length Length of the array + */ + void (*received_unknown_entry)(void *context, uint8_t id, int64_t epoch, const uint8_t* data, uint8_t length); + /** + * Called when a log entry has been received but has no MblMwFnData pointer to forward the data to + */ + MblMwFnData received_unhandled_entry; +} MblMwLogDownloadHandler; + +/** + * Starts data logging + * @param board Board to log data on + * @param overwrite Non-zero if older entries will be overwritten + */ +METAWEAR_API void mbl_mw_logging_start(const MblMwMetaWearBoard* board, uint8_t overwrite); +/** + * Stops data logging + * @param board Board to stop logging + */ +METAWEAR_API void mbl_mw_logging_stop(const MblMwMetaWearBoard* board); +/** + * Flushes logging data (pending writes) to the MMS memory + * Should be called for the MMS when done with logging and ready to download data + * For MMS only. + * @param board Board to stop logging + */ +METAWEAR_API void mbl_mw_logging_flush_page(const MblMwMetaWearBoard* board); +/** + * Clear the logger of saved entries + * @param board Board to remove entries from + */ +METAWEAR_API void mbl_mw_logging_clear_entries(const MblMwMetaWearBoard* board); +/** + * Downloads the log data + * @param board Board to download the log data from + * @param n_notifies How many progress updates to send + * @param handler Handler for processing logger responses + */ +METAWEAR_API void mbl_mw_logging_download(MblMwMetaWearBoard* board, uint8_t n_notifies, const MblMwLogDownloadHandler* handler); +/** + * Retrieves the id value identifying the logger + * @param logger Logger to lookup + * @return Numerical id of the logger + */ +METAWEAR_API uint8_t mbl_mw_logger_get_id(const MblMwDataLogger* logger); +/** + * Retrieves the data signal the logger is recording data for + * @param logger Logger to lookup + * @return Pointer to owning MblMwDataSignal object + */ +METAWEAR_API MblMwDataSignal* mbl_mw_logger_get_signal(const MblMwDataLogger* logger); +/** + * Looks up the MblMwDataLogger object corresponding to the id + * @param board Board to search on + * @param id Numerical id to lookup + * @return Logger object identified by the id, null if no object is found + */ +METAWEAR_API MblMwDataLogger* mbl_mw_logger_lookup_id(const MblMwMetaWearBoard* board, uint8_t id); +/** + * Removes the logger from the board + * @param logger logger to remove + */ +METAWEAR_API void mbl_mw_logger_remove(MblMwDataLogger* logger); +/** + * Subscribes to responses from the data logger + * @param logger Logger to subscribe to + * @param context Pointer to additional data for the callback function + * @param received_data Callback function to handle data received from the logger + */ +METAWEAR_API void mbl_mw_logger_subscribe(MblMwDataLogger* logger, void *context, MblMwFnData received_data); +/** + * Generates a string identifying the data chain the logger is receiving data from. This string is matched with the + * output of mbl_mw_anonymous_datasignal_get_identifier. + * The memory allocated by the function must be freed by calling mbl_mw_memory_free. + * @param logger Calling object + */ +METAWEAR_API const char* mbl_mw_logger_generate_identifier(const MblMwDataLogger* logger); +/** + * Retrieves a data signal representing the length of the log, including timestamps + * @param board Board to get reset_uid from + */ +METAWEAR_API MblMwDataSignal* mbl_mw_logging_get_length_data_signal(const MblMwMetaWearBoard *board); +/** + * Retrieves a data signal representing the current logger time state. This includes the + * reset_uid and time of boot. + * @param board Board to get time from + */ +METAWEAR_API MblMwDataSignal* mbl_mw_logging_get_time_data_signal(const MblMwMetaWearBoard *board); +/** + * Get the latest reset_uid read duing connection + * @param board Board to get reset_uid from + * @return value of reset_uid + */ +METAWEAR_API uint8_t mbl_mw_logging_get_latest_reset_uid(const MblMwMetaWearBoard* board); +/** + * Get the device boot time for a given reset_uid. This reference time + * is automatically calulated at connection time. + * @param board Board to use + * @param reset_uid Reset id + * @return Number of milliseconds since epoch that the given reset_uid occured + */ +METAWEAR_API int64_t mbl_mw_logging_get_reference_time(const MblMwMetaWearBoard *board, uint8_t reset_uid); +/** + * Set the device boot time for a given reset_uid. This reference time + * is used to calcuated real timestamps from logged data. + * @param board Board to use + * @param reset_uid Reset id + * @param reference_epoch New reference epoch (in milliseconds) to use + */ +METAWEAR_API void mbl_mw_logging_set_reference_time(const MblMwMetaWearBoard *board, uint8_t reset_uid, int64_t reference_epoch); + +/** + * Callback functions for handling notifications from the logger + */ +typedef struct { + /** + * Pointer to additional data for the callback functions + */ + void *context; + /** + * Called when a log entry is received + * @param context Pointer to the context field + * @param entry_id Logger id of the entry (logger id) + * @param reset_uid Reset id when this entry was logged (unique counter that increments when the device resets) + * @param entry_tick Raw time when this entry was logged (clock tick the data was logged on in units of 48/32768 seconds - 0.00146484375 sec) + * @param data Raw data (4 bytes) + */ + void (*received_entry)(void *context, uint8_t entry_id, uint8_t reset_uid, uint32_t entry_tick, uint32_t data); + /** + * Called when a progress update is received + * @param context Pointer to the context field + * @param entries_left Number of entries left to download + * @param total_entries Total number of entries + */ + void (*received_progress_update)(void *context, uint32_t entries_left, uint32_t total_entries); + /** + * Called when a log page is complete, use the ready function to indicate when data has been saved + * and you're ready to receive the next page + * @param context Pointer to the context field + * @param caller Object using this function pointer + * @param ready Callback function to handle when ready for the next page + */ + void (*logging_page_completed)(void *context, const MblMwMetaWearBoard* caller, MblMwFnBoardPtr ready); +} MblMwRawLogDownloadHandler; + +/** + * Downloads the raw log data + * @param board Board to download the log data from + * @param n_notifies How many progress updates to send + * @param handler Handler for processing logger responses + */ +METAWEAR_API void mbl_mw_logging_raw_download(MblMwMetaWearBoard* board, uint8_t n_notifies, const MblMwRawLogDownloadHandler* handler); + + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/logging_fwd.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/logging_fwd.h new file mode 100644 index 0000000..f707ea0 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/logging_fwd.h @@ -0,0 +1,22 @@ +/** +* @copyright MbientLab License +* @file logging_fwd.h +* @brief Forward declaration of the MblMwDataLogger type +*/ +#pragma once + +/** + * Logs data from an MblMwDataSignal type letting users retrieve the data at a later time + */ +#ifdef __cplusplus +struct MblMwDataLogger; +#else +typedef struct MblMwDataLogger MblMwDataLogger; +#endif + +/** +* Definition for callback functions that accept an MblMwDataLogger pointer +* @param context Pointer to the context the enclosing function was called with +* @param timer Timer to be used with the function +*/ +typedef void(*MblMwFnDataLoggerPtr)(void *context, MblMwDataLogger* logger); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/macro.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/macro.h new file mode 100644 index 0000000..14f0d65 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/macro.h @@ -0,0 +1,51 @@ +/** + * @copyright MbientLab License + * @file macro.h + * @brief Firmware feature that saves MetaWear commands to the on-board flash memory + */ +#pragma once + +#include "metawearboard_fwd.h" +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Begin macro recording. + * Used to command the board on boot. Commands will survive a reset. + * For example, on boot, flash the LED red. + * For example, when the user drops the metawear (freefall event), vibrate the coin motor. + * For example, renaming the device permanently. + * Every MetaWear command issued will be recorded to the flash memory. + * @param board Calling object + * @param exec_on_boot True if the commands should be executed when the board powers on + */ +METAWEAR_API void mbl_mw_macro_record(MblMwMetaWearBoard *board, uint8_t exec_on_boot); +METAWEAR_API void mbl_mw_macro_record_raw(MblMwMetaWearBoard *board, uint8_t exec_on_boot, void *context, MblMwFnBoardPtrInt ready); +/** + * Ends macro recording. + * An numerical id representing the macro will be passed to the callback function when the operation is complete. + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param commands_recorded Callback function to be executed when the commands are recorded + */ +METAWEAR_API void mbl_mw_macro_end_record(MblMwMetaWearBoard *board, void *context, MblMwFnBoardPtrInt commands_recorded); +/** + * Execute the commands corresponding to the macro ID + * @param board Calling object + * @param id Numerical ID of the macro to execute + */ +METAWEAR_API void mbl_mw_macro_execute(MblMwMetaWearBoard *board, uint8_t id); +/** + * Remove all macros on the flash memory. + * The erase operation will not be performed until you disconnect from the board. + * If you wish to reset the board after the erase operation, use the mbl_mw_debug_reset_after_gc method. + * @param board Calling object + */ +METAWEAR_API void mbl_mw_macro_erase_all(MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/metawearboard.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/metawearboard.h new file mode 100644 index 0000000..ee95b6e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/metawearboard.h @@ -0,0 +1,164 @@ +/** + * @copyright MbientLab License + * @file metawearboard.h + * @brief Functions for communicating with an MblMwMetaWearBoard object + */ +#pragma once + +#include + +#include "anonymous_datasignal_fwd.h" +#include "metawearboard_fwd.h" +#include "model.h" +#include "module.h" + +#include "metawear/platform/btle_connection.h" +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Wrapper class holding characteristics under the + * Device Information + * GATT service + */ +typedef struct { + const char* manufacturer; ///< Device's manufacturer name, characteristic 0x2A29 + const char* model_number; ///< Model number assigned by MbientLab, characteristic 0x2A24 + const char* serial_number; ///< Device's serial number, characteristic 0x2A25 + const char* firmware_revision; ///< Revision of the firmware on the device, characteristic 0x2A26 + const char* hardware_revision; ///< Revision of the hardware on the device, characteristic 0x2A27 +} MblMwDeviceInformation; + +typedef struct { + const char* name; + const uint8_t* extra; + uint8_t extra_len; + uint8_t present; + uint8_t implementation; + uint8_t revision; +} MblMwModuleInfo; + +/** + * Creates an instance of the MblMwMetaWearBoard struct + * @param connection Connection struct the new MblMwMetaWearBoard variable will use for btle communication + * @return Pointer to the newly created struct + */ +METAWEAR_API MblMwMetaWearBoard* mbl_mw_metawearboard_create(const MblMwBtleConnection *connection); +/** + * Frees the memory allocated for the struct + * @param board Pointer to the memory to free + */ +METAWEAR_API void mbl_mw_metawearboard_free(MblMwMetaWearBoard *board); +/** + * Sets how long the API should wait before a required response is received. + * You should increase this value if operations such as API initialization, creating timer, + * loggers, and data processors, and recording commands consistently time out. + * @param board Board to configure + * @param response_time_ms How long to wait for a response, from [0, 4000]ms. Use 0ms for indefinite timeout + */ +METAWEAR_API void mbl_mw_metawearboard_set_time_for_response(MblMwMetaWearBoard* board, uint16_t response_time_ms); +/** + * Initialize the API's internal state. + * This function is non-blocking and will alert the caller when the operation is complete. + * @param board Board to initialize + * @param context Pointer to additional data for the callback function + * @param initialized Callback function to be executed when the board is initialized + */ +METAWEAR_API void mbl_mw_metawearboard_initialize(MblMwMetaWearBoard *board, void *context, MblMwFnBoardPtrInt initialized); +/** + * Removes all data processors and timers from the MetaWear board + * @param board Board to tear down + */ +METAWEAR_API void mbl_mw_metawearboard_tear_down(MblMwMetaWearBoard *board); +/** + * Checks if the board is initialized + * @param board Board to check + * @return Zero if not initialized, non-zero if it is + */ +METAWEAR_API int32_t mbl_mw_metawearboard_is_initialized(const MblMwMetaWearBoard *board); +/** + * Checks module type i.e. what kind of accelerometer is being used + * @param board Board to check + * @param module Module to lookup + * @return Module type used by the board, MBL_MW_MODULE_TYPE_NA if module is not available + * @see MBL_MW_MODULE_ACC_TYPE_MMA8452Q + * @see MBL_MW_MODULE_ACC_TYPE_BMI160 + */ +METAWEAR_API int32_t mbl_mw_metawearboard_lookup_module(const MblMwMetaWearBoard *board, MblMwModule module); +/** + * Determines the board model of the currently connected device. + * Only call this function after the board has been initialized. + * @return Board model, MBL_MW_MODEL_NA if unable to determine + */ +METAWEAR_API MblMwModel mbl_mw_metawearboard_get_model(const MblMwMetaWearBoard* board); +/** + * Determines the board model of the currently connected device. + * Only call this function after the board has been initialized. + * @return Friendly name representing the board model + */ +METAWEAR_API const char* mbl_mw_metawearboard_get_model_name(const MblMwMetaWearBoard* board); +/** + * Retrieves supported characteristics from the Device Information service. + * The memory allocated by the function must be freed by calling mbl_mw_memory_free. + * @return Struct holding the characteristics + */ +METAWEAR_API const MblMwDeviceInformation* mbl_mw_metawearboard_get_device_information(const MblMwMetaWearBoard* board); +/** + * Returns information about the onboard modules + * @param board Calling object + * @param size Pointer to where the size of the returned array will be written to + * @return Array of info objects + */ +METAWEAR_API MblMwModuleInfo* mbl_mw_metawearboard_get_module_info(const MblMwMetaWearBoard* board, uint32_t* size); +/** + * Serializes the API state. + * The memory allocated by the function must be freed by calling mbl_mw_memory_free. + * @param board Board to serialize + * @param size Pointer to where the size of the returned byte array will be written to + * @return Byte array of the serialized state + */ +METAWEAR_API uint8_t* mbl_mw_metawearboard_serialize(const MblMwMetaWearBoard* board, uint32_t* size); +/** + * Deserializes API state. + * This function must be executed before calling mbl_mw_metawearboard_initialize. + * @param board Board to deserialize + * @param state Byte array holding the the information state + * @param size Byte array size + * @return MBL_MW_STATUS_OK if successful, MBL_MW_STATUS_ERROR_SERIALIZATION_FORMAT if failed + */ +METAWEAR_API int32_t mbl_mw_metawearboard_deserialize(MblMwMetaWearBoard* board, uint8_t* state, uint32_t size); +/** + * Reads the current state of the board and creates anonymous data signals based on what data is being logged. + * If this task failed, a null pointer will be passed into the `anonymous_signals` parameter + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param created Callback function to be executed once the task is completed. + */ +METAWEAR_API void mbl_mw_metawearboard_create_anonymous_datasignals(MblMwMetaWearBoard* board, void *context, MblMwFnAnonSignalArray created); + +/** + * Wrapper class containing functions for receiving callbacks throughout the DFU process + */ +typedef struct { + void *context; + void (*on_dfu_started)(void *context); + void (*on_dfu_cancelled)(void *context); + void (*on_transfer_percentage)(void *context, int32_t percentage); + void (*on_successful_file_transferred)(void *context); + void (*on_error)(void *context, const char *errorMessage); +} MblMwDfuDelegate; + +/** + * Starts the DFU process and updloads the given file to the device + * @param board Calling object + * @param delegate Struct the function will forward DFU progress updates to + * @param filename Path to firmware bin file + */ +METAWEAR_API void mbl_mw_metawearboard_perform_dfu(MblMwMetaWearBoard *board, const MblMwDfuDelegate *delegate, const char *filename); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/metawearboard_fwd.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/metawearboard_fwd.h new file mode 100644 index 0000000..c27f349 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/metawearboard_fwd.h @@ -0,0 +1,31 @@ +/** + * @copyright MbientLab License + * @file metawearboard_fwd.h + * @brief Forward declarations for the MblMwMetaWearBoard type + */ + +#pragma once + +#include + +/** + * Software representation of a physical MetaWear board + */ +#ifdef __cplusplus +struct MblMwMetaWearBoard; +#else +typedef struct MblMwMetaWearBoard MblMwMetaWearBoard; +#endif + +/** + * Definition for callback functions that accept an MblMwMetaWearBoard pointer and an int32 + * @param context Pointer to the context the enclosing function was called with + * @param board Board pointer to be used with the function + * @param value Additional value passed to the function for context specific callbacks + */ +typedef void(*MblMwFnBoardPtrInt)(void *context, MblMwMetaWearBoard* board, int32_t value); +/** + * Definition for callback functions that accept an MblMwMetaWearBoard pointer + * @param board Board pointer to be used with the function + */ +typedef void(*MblMwFnBoardPtr)(const MblMwMetaWearBoard* board); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/model.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/model.h new file mode 100644 index 0000000..3974c6e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/model.h @@ -0,0 +1,26 @@ +/** + * @copyright MbientLab License (LICENSE.md) + * @file model.h + * @brief + */ +#pragma once + +/** + * Available MetaWear models + */ +typedef enum { + MBL_MW_MODEL_NA = -1, + MBL_MW_MODEL_METAWEAR_R, + MBL_MW_MODEL_METAWEAR_RG, + MBL_MW_MODEL_METAWEAR_RPRO, + MBL_MW_MODEL_METAWEAR_C, + MBL_MW_MODEL_METAWEAR_CPRO, + MBL_MW_MODEL_METAENV, + MBL_MW_MODEL_METADETECT, + MBL_MW_MODEL_METAHEALTH, + MBL_MW_MODEL_METATRACKER, + MBL_MW_MODEL_METAMOTION_R, + MBL_MW_MODEL_METAMOTION_RL, + MBL_MW_MODEL_METAMOTION_C, + MBL_MW_MODEL_METAMOTION_S +} MblMwModel; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/module.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/module.h new file mode 100644 index 0000000..f3eaab1 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/module.h @@ -0,0 +1,38 @@ +/** + * @copyright MbientLab License + * @file module.h + */ + +#pragma once + +/** + * Sensors or peripherals supported by the firmware. Different board skews have different module combinations, + * use mbl_mw_metawearboard_lookup_module to check if a module is present on your board + */ +typedef enum { + MBL_MW_MODULE_SWITCH = 1, + MBL_MW_MODULE_LED, + MBL_MW_MODULE_ACCELEROMETER, + MBL_MW_MODULE_TEMPERATURE, + MBL_MW_MODULE_GPIO, + MBL_MW_MODULE_NEO_PIXEL, + MBL_MW_MODULE_IBEACON, + MBL_MW_MODULE_HAPTIC, + MBL_MW_MODULE_DATA_PROCESSOR, + MBL_MW_MODULE_EVENT, + MBL_MW_MODULE_LOGGING, + MBL_MW_MODULE_TIMER, + MBL_MW_MODULE_I2C, + MBL_MW_MODULE_MACRO = 0xf, + MBL_MW_MODULE_CONDUCTANCE, + MBL_MW_MODULE_SETTINGS, + MBL_MW_MODULE_BAROMETER, + MBL_MW_MODULE_GYRO, + MBL_MW_MODULE_AMBIENT_LIGHT, + MBL_MW_MODULE_MAGNETOMETER, + MBL_MW_MODULE_HUMIDITY, + MBL_MW_MODULE_COLOR_DETECTOR, + MBL_MW_MODULE_PROXIMITY, + MBL_MW_MODULE_SENSOR_FUSION, + MBL_MW_MODULE_DEBUG = 0xfe +} MblMwModule; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/settings.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/settings.h new file mode 100644 index 0000000..1b41d1a --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/settings.h @@ -0,0 +1,194 @@ +/** + * @copyright MbientLab License + * @file settings.h + * @brief Configures Bluetooth Low Energy advertisement and connection settings + */ +#pragma once + +#include + +#include "datasignal_fwd.h" +#include "event_fwd.h" +#include "metawearboard_fwd.h" + +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//@{ +///< Indices for component values of the battery data signal, to be used with mbl_mw_datasignal_get_component +const uint8_t MBL_MW_SETTINGS_BATTERY_VOLTAGE_INDEX = 0, + MBL_MW_SETTINGS_BATTERY_CHARGE_INDEX = 1; +//@} + +/** + * Types of BLE addresses + */ +const uint8_t MBL_MW_ADDRESS_TYPE_PUBLIC = 0, + MBL_MW_ADDRESS_TYPE_RANDOM_STATIC = 1, + MBL_MW_ADDRESS_TYPE_PRIVATE_RESOLVABLE = 2, + MBL_MW_ADDRESS_TYPE_PRIVATE_NON_RESOLVABLE = 3; + +//@{ +///< Values returned if the power or charge statuses are not supported +const int32_t MBL_MW_SETTINGS_POWER_STATUS_UNSUPPORTED = -1, + MBL_MW_SETTINGS_CHARGE_STATUS_UNSUPPORTED = -1; +//@} + +/** + * Whitelist filter modes + */ +typedef enum { + MBL_MW_WHITELIST_FILTER_ALLOW_FROM_ANY = 0, + MBL_MW_WHITELIST_FILTER_SCAN_REQUESTS = 1, + MBL_MW_WHITELIST_FILTER_CONNECTION_REQUESTS = 2, + MBL_MW_WHITELIST_FILTER_SCAN_AND_CONNECTION_REQUESTS = 3 +} MblMwWhitelistFilter; + +typedef enum { + MBL_MW_BLE_AD_TYPE_CONNECTED_UNDIRECTED = 0, + MBL_MW_BLE_AD_TYPE_CONNECTED_DIRECTED = 1 +} MblMwBleAdType; + +/** + * BLE MAC Address + */ +typedef struct { + uint8_t address_type; ///< Types of BLE address: MBL_MW_ADDRESS_TYPE_* + uint8_t address[6]; ///< MAC Address - Little Endian (LSB First) +} MblMwBtleAddress; + +/** + * Retrieves an event pointer representing a disconnect event + * @param board Board the event is fired on + * @return Pointer to the disconnect event + */ +METAWEAR_API MblMwEvent* mbl_mw_settings_get_disconnect_event(const MblMwMetaWearBoard *board); +/** + * Retrieves the data signal representing battery state + * @param board Calling object + * @return Pointer to the battery state signal + */ +METAWEAR_API MblMwDataSignal* mbl_mw_settings_get_battery_state_data_signal(const MblMwMetaWearBoard *board); +/** + * Retrieves the data signal representing the device GAP (MAC) address + * @param board Calling object + * @return Pointer to the mac signal + */ +METAWEAR_API MblMwDataSignal* mbl_mw_settings_get_mac_data_signal(const MblMwMetaWearBoard *board); +/** + * Retrieves the data signal representing the power status + * @param board Calling object + * @return Pointer to the power status signal, nullptr if unsupported + */ +METAWEAR_API MblMwDataSignal* mbl_mw_settings_get_power_status_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing the charge status + * @param board Calling object + * @return Pointer to the charge status signal, nullptr if unsupported + */ +METAWEAR_API MblMwDataSignal* mbl_mw_settings_get_charge_status_data_signal(const MblMwMetaWearBoard* board); +/** + * Sets the advertisement name + * Can be used to rename the device + * @param board Board to modify + * @param device_name Byte array containing the device name, max 8 ASCII characters + * @param len Length of the array + */ +METAWEAR_API void mbl_mw_settings_set_device_name(const MblMwMetaWearBoard *board, const uint8_t *device_name, uint8_t len); +/** + * @deprecated In v0.14.0, use mbl_mw_settings_set_ad_parameters instead + */ +METAWEAR_API void mbl_mw_settings_set_ad_interval(const MblMwMetaWearBoard *board, uint16_t interval, uint8_t timeout); +/** + * Configures Bluetooth LE ad parameters + * @param board Calling object + * @param interval Advertisement interval, between [0, 65535] milliseconds + * @param timeout Advertisement timeout, between [0, 180] seconds where 0 indicates no timeout + * @param type Advertisement type, ignored if unsupported on current firmware + */ +METAWEAR_API void mbl_mw_settings_set_ad_parameters(const MblMwMetaWearBoard *board, uint16_t interval, uint8_t timeout, MblMwBleAdType type); +/** + * Sets advertising transmitting power. If a non valid value is set, the nearest valid value will be used instead + * @param board Board to set the TX power + * @param tx_power Valid values are: 4, 0, -4, -8, -12, -16, -20, -30 + */ +METAWEAR_API void mbl_mw_settings_set_tx_power(const MblMwMetaWearBoard *board, int8_t tx_power); +/** + * Starts advertising + * @param board Board to start btle advertisement + */ +METAWEAR_API void mbl_mw_settings_start_advertising(const MblMwMetaWearBoard *board); +/** + * Sets scan response + * @param board Board to modify + * @param response Scan response as a byte array + * @param len Length of the array + */ +METAWEAR_API void mbl_mw_settings_set_scan_response(const MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len); +/** + * Sets connection parameters + * @param board Board to modify + * @param min_conn_interval Connection interval lower bound, min 7.5ms + * @param max_conn_interval Connection interval upper bound, max 4000ms + * @param latency Number of connection intervals to skip, betwen [0, 1000] + * @param timeout Max time between data exchanges until the connection is considered to be lost, between [10, 32000]ms + */ +METAWEAR_API void mbl_mw_settings_set_connection_parameters(const MblMwMetaWearBoard *board, float min_conn_interval, float max_conn_interval, + uint16_t latency, uint16_t timeout); +/** + * Adds MAC Addresses for Whitelist filtering + * @param board Board to modify + * @param index Whitelist MAC address in range [1, 8], must start at 1 and go in increasing order + * @param address Address to add + */ +METAWEAR_API void mbl_mw_settings_add_whitelist_address(const MblMwMetaWearBoard *board, uint8_t index, const MblMwBtleAddress *address); +/** + * Adds MAC Addresses for Whitelist filtering + * @param board Board to modify + * @param index Whitelist MAC address in range [1, 8], must start at 1 and go in increasing order + * @param address Address to add + */ +METAWEAR_API MblMwDataSignal* mbl_mw_settings_get_whitelist_data_signal(MblMwMetaWearBoard* board, uint8_t index); +/** + * Sets connection parameters + * @param board Board to modify + * @param mode Whitelist filter mode + */ +METAWEAR_API void mbl_mw_settings_set_whitelist_filter_mode(const MblMwMetaWearBoard *board, MblMwWhitelistFilter mode); +/** + * Retrieves the firmware build id, used for identifying custom firmware build variants + * @param board Calling object + */ +METAWEAR_API uint8_t mbl_mw_settings_get_firmware_build_id(const MblMwMetaWearBoard *board); +/** + * Reads the current power status if available. The callback function will be called with: + * 1 - power source is attached + * 0 - no power source atached + * -1 - feature not supported + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param handler Callback function that is executed when the task is finished + */ +METAWEAR_API void mbl_mw_settings_read_current_power_status(MblMwMetaWearBoard* board, void* context, MblMwFnBoardPtrInt handler); +/** + * Reads the current charge status. The callback function will be called with: + * 1 - battery is charging + * 0 - battery is not charging + * -1 - feature not supported + */ +METAWEAR_API void mbl_mw_settings_read_current_charge_status(MblMwMetaWearBoard* board, void* context, MblMwFnBoardPtrInt handler); +/** + * Turns on the 3V regulator + * Needed if IOs / peripherals need 3V power from the MetaSensor + * For MMS only, will be ignored for all others + * @param board Board to modify + * @param index 0: Disable, 1: Enable + */ +METAWEAR_API void mbl_mw_settings_enable_3V_regulator(const MblMwMetaWearBoard *board, uint8_t enable); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/status.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/status.h new file mode 100644 index 0000000..a8f903f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/status.h @@ -0,0 +1,26 @@ +/** +* @copyright MbientLab License (LICENSE.md) +* @file status.h +* @brief Status codes for the library +*/ + +#pragma once + +#include + +/** Code executed normally, no errors or warnings */ +const int32_t MBL_MW_STATUS_OK= 0; +/** Data unexpectedly received from a sensor. This could happen if the library connects to an already setup board */ +const int32_t MBL_MW_STATUS_WARNING_UNEXPECTED_SENSOR_DATA= 1; +/** Invalid processor passed into a dataprocessor function */ +const int32_t MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE= 2; +/** Processor not supported for the data signal */ +const int32_t MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR = 4; +/** Invalid response receieved from the MetaWear notify characteristic */ +const int32_t MBL_MW_STATUS_WARNING_INVALID_RESPONSE = 8; +/** Timeout occured during an asynchronous operation */ +const int32_t MBL_MW_STATUS_ERROR_TIMEOUT = 16; +/** Cannot restore API state given the input serialization format */ +const int32_t MBL_MW_STATUS_ERROR_SERIALIZATION_FORMAT = 32; +/** Failed to enable notifications */ +const int32_t MBL_MW_STATUS_ERROR_ENABLE_NOTIFY = 64; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/timer.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/timer.h new file mode 100644 index 0000000..624ab55 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/timer.h @@ -0,0 +1,71 @@ +/** + * @copyright MbientLab License + * @file timer.h + * @brief On board timer for scheduling MetaWear commands + */ +#pragma once + +#include + +#include "metawearboard_fwd.h" +#include "timer_fwd.h" + +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Creates a timer that will run for a set number of repetitions. + * A pointer representing the timer will be passed to the user through a callback function + * @param board Board the timer belongs to + * @param period How often to + * @param repetitions Number of events the timer will fire + * @param delay Zero if the tiemr should immediately fire, non-zero to delay the first event + * @param context Pointer to additional data for the callback function + * @param received_timer Callback function to be executed when the timer is created + */ +METAWEAR_API void mbl_mw_timer_create(MblMwMetaWearBoard *board, uint32_t period, uint16_t repetitions, uint8_t delay, void *context, MblMwFnTimerPtr received_timer); +/** + * Creates a timer that will run indefinitely. + * A pointer representing the timer will be passed to the user through a callback function + * @param board Board the timer belongs to + * @param period How often to + * @param delay Zero if the tiemr should immediately fire, non-zero to delay the first event + * @param context Pointer to additional data for the callback function + * @param received_timer Callback function to be executed when the timer is created + */ +METAWEAR_API void mbl_mw_timer_create_indefinite(MblMwMetaWearBoard *board, uint32_t period, uint8_t delay, void *context, MblMwFnTimerPtr received_timer); +/** + * Retrieves the id value identifying the timer + * @param timer Timer to lookup + * @return Numerical id of the timer + */ +METAWEAR_API uint8_t mbl_mw_timer_get_id(const MblMwTimer* timer); +/** + * Looks up the MblMwTimer object corresponding to the id + * @param board Board to search on + * @param id Numerical id to lookup + * @return Timer object identified by the id, null if no object is found + */ +METAWEAR_API MblMwTimer* mbl_mw_timer_lookup_id(const MblMwMetaWearBoard* board, uint8_t id); +/** + * Starts a timer + * @param timer Timer to start + */ +METAWEAR_API void mbl_mw_timer_start(const MblMwTimer* timer); +/** + * Stops a timer + * @param timer Timer to stop + */ +METAWEAR_API void mbl_mw_timer_stop(const MblMwTimer* timer); +/** + * Removes the timer from the board + * @param timer Timer to remove + */ +METAWEAR_API void mbl_mw_timer_remove(MblMwTimer* timer); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/timer_fwd.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/timer_fwd.h new file mode 100644 index 0000000..a3e2e5e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/timer_fwd.h @@ -0,0 +1,23 @@ +/** + * @copyright MbientLab License + * @file timer_fwd.h + * @brief Forward declaration of the MblMwTimer type + */ +#pragma once + +/** + * On board timer that periodically fires events. An MblMwTimer pointer can be casted as an MblMwEvent pointer + * and used with any function that accepts an MblMwEvent pointer. + */ +#ifdef __cplusplus +struct MblMwTimer; +#else +typedef struct MblMwTimer MblMwTimer; +#endif + +/** + * Definition for callback functions that accept an MblMwTimer pointer + * @param context Pointer to the context the enclosing function was called with + * @param timer Timer to be used with the function + */ +typedef void (*MblMwFnTimerPtr)(void *context, MblMwTimer* timer); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/types.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/types.h new file mode 100644 index 0000000..064ed3c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/core/types.h @@ -0,0 +1,113 @@ +/** + * @copyright MbientLab License (LICENSE.md) + * @file types.h + * @brief Non basic types encapsulating sensor data + */ +#pragma once + +#include + +/** + * Tuple combining float data on a 3D cartesian coordinate system + */ +typedef struct { + float x; ///< Data corresponding to the x-axis + float y; ///< Data corresponding to the y-axis + float z; ///< Data corresponding to the z-axis +} MblMwCartesianFloat; + +/** + * Tuple holding battery state information + */ +typedef struct { + uint16_t voltage; ///< Voltage level, in mV + uint8_t charge; ///< Percent charged, between [0, 100] percent +} MblMwBatteryState; + +/** + * Tuple wrapping ADC data from the TCS34725 color detector + */ +typedef struct { + uint16_t clear; ///< ADC value from an unfiltered diode + uint16_t red; ///< ADC value from a red filtered diode + uint16_t green; ///< ADC value from a green filtered diode + uint16_t blue; ///< ADC value from a blue filtered diode +} MblMwTcs34725ColorAdc; + +/** + * 4-element float vector holding Euler angles, all values are in degrees + */ +typedef struct { + float heading; + float pitch; + float roll; + float yaw; +} MblMwEulerAngles; + +/** + * 4-element float vector containing a normalized quaternion value + */ +typedef struct { + float w; + float x; + float y; + float z; +} MblMwQuaternion; + +/** + * Variant of the MblMwCartesianFloat struct that also reports data accuracy + */ +typedef struct { + float x; + float y; + float z; + uint8_t accuracy; +} MblMwCorrectedCartesianFloat; + +/** + * Internal stack overflow state + */ +typedef struct { + uint16_t length; + uint8_t assert_en; +} MblMwOverflowState; + +/** + * Enumeration of sensor orientations + * @author Eric Tsai + */ +typedef enum { + MBL_MW_SENSOR_ORIENTATION_FACE_UP_PORTRAIT_UPRIGHT, + MBL_MW_SENSOR_ORIENTATION_FACE_UP_PORTRAIT_UPSIDE_DOWN, + MBL_MW_SENSOR_ORIENTATION_FACE_UP_LANDSCAPE_LEFT, + MBL_MW_SENSOR_ORIENTATION_FACE_UP_LANDSCAPE_RIGHT, + MBL_MW_SENSOR_ORIENTATION_FACE_DOWN_PORTRAIT_UPRIGHT, + MBL_MW_SENSOR_ORIENTATION_FACE_DOWN_PORTRAIT_UPSIDE_DOWN, + MBL_MW_SENSOR_ORIENTATION_FACE_DOWN_LANDSCAPE_LEFT, + MBL_MW_SENSOR_ORIENTATION_FACE_DOWN_LANDSCAPE_RIGHT +} MblMwSensorOrientation; + +/** + * Internal clock for logger timestamps + */ +typedef struct { + int64_t epoch; + uint8_t reset_uid; +} MblMwLoggingTime; + +/** + * Sensor fusion calibration state + */ +typedef struct { + uint8_t accelrometer; + uint8_t gyroscope; + uint8_t magnetometer; +} MblMwCalibrationState; + +/** + * Wrapper class encapsulating responses from the Bosch tap detector + */ +typedef struct { + uint8_t type; ///< 1 if double tap, 2 if single tap + uint8_t sign; ///< 0 if positive, 1 if negative +} MblMwBoschTap; \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.cpp new file mode 100644 index 0000000..3df1a61 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.cpp @@ -0,0 +1,343 @@ +#include "dfu_operations.h" + +#include + +DfuOperations::DfuOperations(const MblMwMetaWearBoard* board, const MblMwDfuDelegate *delegate) : dfuRequests(new DFUOperationsDetails(board)), fileRequests(new FileOperations(*this, board)) { + memcpy(&this->dfuDelegate, delegate, sizeof(MblMwDfuDelegate)); +} + +DfuOperations::~DfuOperations() { + +} + +void DfuOperations::cancelDFU() { + //NSLog(@"cancelDFU"); + dfuRequests->resetSystem(); + dfuDelegate.on_dfu_cancelled(dfuDelegate.context); +} + +//-(void)performDFUOnFiles:(NSURL *)softdeviceURL bootloaderURL:(NSURL *)bootloaderURL firmwareType:(MBL_DfuFirmwareTypes)firmwareType +//{ +// isPerformedOldDFU = NO; +// [self initFirstMBL_FileOperations]; +// [self initSecondMBL_FileOperations]; +// [self initParameters]; +// self.dfuFirmwareType = firmwareType; +// [fileRequests openFile:softdeviceURL]; +// [fileRequests2 openFile:bootloaderURL]; +// [dfuRequests enableNotification]; +// [dfuRequests startDFU:firmwareType]; +// [dfuRequests writeFilesSizes:(uint32_t)fileRequests.binFileSize bootloaderSize:(uint32_t)fileRequests2.binFileSize]; +//} + +//-(void)performDFUOnFile:(NSURL *)firmwareURL firmwareType:(MBL_DfuFirmwareTypes)firmwareType +//{ +// isPerformedOldDFU = NO; +// firmwareFile = firmwareURL; +// [self initFirstMBL_FileOperations]; +// isStartingSecondFile = NO; +// [self initParameters]; +// self.dfuFirmwareType = firmwareType; +// [fileRequests openFile:firmwareURL]; +// [dfuRequests enableNotification]; +// [dfuRequests startDFU:firmwareType]; +// [dfuRequests writeFileSize:(uint32_t)fileRequests.binFileSize]; +//} + +void DfuOperations::perfromDFUOnZipFile(const char *zipFilename) { + isVersionCharacteristicExist = true; + isPerformedOldDFU = false; + //firmwareFile = firmwareURL; + //[self initFirstFileOperations]; + //isStartingSecondFile = NO; + //[self initParameters]; + //self.dfuFirmwareType = firmwareType; + fileRequests->openZip(zipFilename); + //[dfuRequests enableNotification]; + dfuRequests->startDFU(APPLICATION); + dfuRequests->writeFileSize(static_cast(fileRequests->binFileSize)); +} + +void DfuOperations::performOldDFUOnFile(const char *firmwareFilename) { + isVersionCharacteristicExist = false; + isPerformedOldDFU = true; + if (firmwareFilename) { +// [self initFirstMBL_FileOperations]; +// [self initParameters]; + fileRequests->openFile(firmwareFilename); +// [dfuRequests enableNotification]; + dfuRequests->startOldDFU(); + dfuRequests->writeFileSizeForOldDFU(static_cast(fileRequests->binFileSize)); + } else { + const char *errorMessage = "Old DFU only supports Application upload"; + dfuDelegate.on_error(dfuDelegate.context, errorMessage); + dfuRequests->resetSystem(); + } +} + +//-(void)initParameters +//{ +// startTime = [NSDate date]; +// binFileSize = 0; +// isStartingSecondFile = NO; +//} + +//-(void)initFirstMBL_FileOperations +//{ +// fileRequests = [[MBL_FileOperations alloc]initWithDelegate:self +// blePeripheral:self.bluetoothPeripheral +// bleCharacteristic:self.dfuPacketCharacteristic]; +//} +// +//-(void)initSecondMBL_FileOperations +//{ +// fileRequests2 = [[MBL_FileOperations alloc]initWithDelegate:self +// blePeripheral:self.bluetoothPeripheral +// bleCharacteristic:self.dfuPacketCharacteristic]; +//} + +void DfuOperations::startSendingFile() { + // if (self.dfuFirmwareType == SOFTDEVICE || self.dfuFirmwareType == SOFTDEVICE_AND_BOOTLOADER) { + // NSLog(@"waiting 10 seconds before sending file ..."); + // //Delay of 10 seconds is required in order to update Softdevice in SDK 6.0 + // dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + // dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + // [dfuRequests enablePacketNotification]; + // [dfuRequests receiveFirmwareImage]; + // [fileRequests writeNextPacket]; + // [dfuDelegate onDFUStarted]; + // }); + // } + // else { + dfuRequests->enablePacketNotification(); + dfuRequests->receiveFirmwareImage(); + fileRequests->writeNextPacket(); + dfuDelegate.on_dfu_started(dfuDelegate.context); + // } + // if (self.dfuFirmwareType == SOFTDEVICE_AND_BOOTLOADER) { + // [dfuDelegate onSoftDeviceUploadStarted]; + // } +} +// +//-(NSString *) responseErrorMessage:(MBL_DfuOperationStatus)errorCode +//{ +// switch (errorCode) { +// case OPERATION_FAILED_RESPONSE: +// return @"Operation Failed"; +// break; +// case OPERATION_INVALID_RESPONSE: +// return @"Invalid Response"; +// break; +// case OPERATION_NOT_SUPPORTED_RESPONSE: +// return @"Operation Not Supported"; +// break; +// case DATA_SIZE_EXCEEDS_LIMIT_RESPONSE: +// return @"Data Size Exceeds"; +// break; +// case CRC_ERROR_RESPONSE: +// return @"CRC Error"; +// break; +// default: +// return @"unknown Error"; +// break; +// } +//} + +void DfuOperations::processRequestedCode() { +// NSLog(@"processsRequestedCode"); + switch (dfuResponse.requestedCode) { + case START_DFU_REQUEST: +// NSLog(@"Requested code is StartDFU now processing response status"); + processStartDFUResponseStatus(); + break; + case RECEIVE_FIRMWARE_IMAGE_REQUEST: +// NSLog(@"Requested code is Receive Firmware Image now processing response status"); + processReceiveFirmwareResponseStatus(); + break; + case VALIDATE_FIRMWARE_REQUEST: +// NSLog(@"Requested code is Validate Firmware now processing response status"); + processValidateFirmwareResponseStatus(); + break; + case INITIALIZE_DFU_PARAMETERS_REQUEST: +// NSLog(@"Requested code is Initialize DFU Parameters now processing response status"); + processInitPacketResponseStatus(); + break; + default: +// NSLog(@"invalid Requested code in DFU Response %d",dfuResponse.requestedCode); + break; + } +} + +void DfuOperations::processStartDFUResponseStatus() { +// NSLog(@"processStartDFUResponseStatus"); +// NSString *errorMessage = [NSString stringWithFormat:@"Error on StartDFU\n Message: %@",[self responseErrorMessage:dfuResponse.responseStatus]]; + switch (dfuResponse.responseStatus) { + case OPERATION_SUCCESSFUL_RESPONSE: +// NSLog(@"successfully received startDFU notification"); + if (isVersionCharacteristicExist) { + dfuRequests->sendInitPacket(fileRequests->metaDataFile, static_cast(fileRequests->metaDataFileSize)); + } else { + startSendingFile(); + } + break; + case OPERATION_NOT_SUPPORTED_RESPONSE: +// if (!isPerformedOldDFU) { +// NSLog(@"device has old DFU. switching to old DFU ..."); +// [self performOldDFUOnFile:firmwareFile]; +// } +// else { +// NSLog(@"Operation not supported"); +// NSLog(@"Firmware Image failed, Error Status: %@",[self responseErrorMessage:dfuResponse.responseStatus]); +// NSString *errorMessage = [NSString stringWithFormat:@"Error on StartDFU\n Message: %@",[self responseErrorMessage:dfuResponse.responseStatus]]; + dfuDelegate.on_error(dfuDelegate.context, "Error on StartDFU: OPERATION_NOT_SUPPORTED_RESPONSE"); + dfuRequests->resetSystem(); +// } + break; + + default: +// NSLog(@"StartDFU failed, Error Status: %@",[self responseErrorMessage:dfuResponse.responseStatus]); + dfuDelegate.on_error(dfuDelegate.context, "Error on StartDFU: Unkown Response"); + dfuRequests->resetSystem(); + break; + } +} + +void DfuOperations::processInitPacketResponseStatus() { +// NSLog(@"processInitPacketResponseStatus"); + if (dfuResponse.responseStatus == OPERATION_SUCCESSFUL_RESPONSE) { +// NSLog(@"successfully received initPacket notification"); + startSendingFile(); + } + else { + //NSLog(@"unsuccessfull initPacket notification %d",dfuResponse.responseStatus); +// NSLog(@"Init Packet failed, Error Status: %@",[self responseErrorMessage:dfuResponse.responseStatus]); +// NSString *errorMessage = [NSString stringWithFormat:@"Error on Init Packet\n Message: %@",[self responseErrorMessage:dfuResponse.responseStatus]]; +// [dfuDelegate onError:errorMessage]; +// [dfuRequests resetSystem]; + dfuDelegate.on_error(dfuDelegate.context, "Error on Init Packet"); + dfuRequests->resetSystem(); + } +} + +void DfuOperations::processReceiveFirmwareResponseStatus() { +// NSLog(@"processReceiveFirmwareResponseStatus"); + if (dfuResponse.responseStatus == OPERATION_SUCCESSFUL_RESPONSE) { +// NSLog(@"successfully received notification for whole File transfer"); + dfuRequests->validateFirmware(); + } + else { +// NSLog(@"Firmware Image failed, Error Status: %@",[self responseErrorMessage:dfuResponse.responseStatus]); +// NSString *errorMessage = [NSString stringWithFormat:@"Error on Receive Firmware Image\n Message: %@",[self responseErrorMessage:dfuResponse.responseStatus]]; + dfuDelegate.on_error(dfuDelegate.context, "Error on Receive Firmware Image"); + dfuRequests->resetSystem(); + } +} + +void DfuOperations::processValidateFirmwareResponseStatus() { +// NSLog(@"processValidateFirmwareResponseStatus"); + if (dfuResponse.responseStatus == OPERATION_SUCCESSFUL_RESPONSE) { +// NSLog(@"succesfully received notification for ValidateFirmware"); + dfuRequests->activateAndReset(); +// [self calculateDFUTime]; + dfuDelegate.on_successful_file_transferred(dfuDelegate.context); + } + else { +// NSLog(@"Firmware validate failed, Error Status: %@",[self responseErrorMessage:dfuResponse.responseStatus]); +// NSString *errorMessage = [NSString stringWithFormat:@"Error on Validate Firmware Request\n Message: %@",[self responseErrorMessage:dfuResponse.responseStatus]]; + dfuDelegate.on_error(dfuDelegate.context, "Error on Validate Firmware Request"); + dfuRequests->resetSystem(); + } +} + +void DfuOperations::processPacketNotification() { + //NSLog(@"received Packet Received Notification"); +// if (isStartingSecondFile) { +// if (fileRequests2.writingPacketNumber < fileRequests2.numberOfPackets) { +// [fileRequests2 writeNextPacket]; +// } +// } +// else { + if (fileRequests->writingPacketNumber < fileRequests->numberOfPackets) { + fileRequests->writeNextPacket(); + } +// } +} + +void DfuOperations::processDFUResponse(const uint8_t *data, uint8_t len) { +// NSLog(@"processDFUResponse"); + setDFUResponseStruct(data, len); + if (dfuResponse.responseCode == RESPONSE_CODE) { + processRequestedCode(); + } + else if (dfuResponse.responseCode == PACKET_RECEIPT_NOTIFICATION_RESPONSE) { + processPacketNotification(); + } +} + +void DfuOperations::setDFUResponseStruct(const uint8_t *data, uint8_t len) { + while (len < 3) { } // TODO: Remove me + dfuResponse.responseCode = data[0]; + dfuResponse.requestedCode = data[1]; + dfuResponse.responseStatus = data[2]; +} + +// +//-(void)setMBL_DFUOperationsDetails +//{ +// [self.dfuRequests setPeripheralAndOtherParameters:self.bluetoothPeripheral +// controlPointCharacteristic:self.dfuControlPointCharacteristic +// packetCharacteristic:self.dfuPacketCharacteristic]; +//} +// +//-(void)calculateDFUTime +//{ +// finishTime = [NSDate date]; +// self.uploadTimeInSeconds = [finishTime timeIntervalSinceDate:startTime]; +// NSLog(@"upload time in sec: %u", (int)self.uploadTimeInSeconds); +//} +// +//#pragma mark - MBL_BLEOperations delegates +// +//-(void)onDeviceConnected:(CBPeripheral *)peripheral withPacketCharacteristic:(CBCharacteristic *)dfuPacketCharacteristic andControlPointCharacteristic:(CBCharacteristic *)dfuControlPointCharacteristic +//{ +// self.bluetoothPeripheral = peripheral; +// self.dfuPacketCharacteristic = dfuPacketCharacteristic; +// self.dfuControlPointCharacteristic = dfuControlPointCharacteristic; +// [self setMBL_DFUOperationsDetails]; +// [dfuDelegate onDeviceConnected:peripheral]; +//} +// +//-(void)onDeviceDisconnected:(CBPeripheral *)peripheral +//{ +// [dfuDelegate onDeviceDisconnected:peripheral]; +//} +// + + +// FileOperations delegates + +void DfuOperations::onTransferPercentage(int32_t percentage) { +// //NSLog(@"MBL_DFUOperations: onTransferPercentage %d",percentage); + dfuDelegate.on_transfer_percentage(dfuDelegate.context, percentage); +} +void DfuOperations::onAllPacketsTranferred() { +// NSLog(@"MBL_DFUOperations: onAllPacketsTransfered"); +// if (isStartingSecondFile) { +// [dfuDelegate onBootloaderUploadCompleted]; +// } +// else if (self.dfuFirmwareType == SOFTDEVICE_AND_BOOTLOADER) { +// isStartingSecondFile = YES; +// NSLog(@"Firmware type is Softdevice plus Bootloader. now upload bootloader ..."); +// [dfuDelegate onSoftDeviceUploadCompleted]; +// [dfuDelegate onBootloaderUploadStarted]; +// [fileRequests2 writeNextPacket]; +// } +} +void DfuOperations::onFileOpened(size_t) { +// NSLog(@"onFileOpened file size: %d", (int)fileSizeOfBin); +// binFileSize += fileSizeOfBin; +} +void DfuOperations::onError(const std::string &errorMessage) { +// NSLog(@"MBL_DFUOperations: onError"); + dfuDelegate.on_error(dfuDelegate.context, errorMessage.c_str()); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.h new file mode 100644 index 0000000..f2463c6 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.h @@ -0,0 +1,99 @@ +#pragma once + +// +// MBL_DFUOperations.h +// nRFDeviceFirmwareUpdate +// +// Created by Nordic Semiconductor on 18/06/14. +// Copyright (c) 2014 Nordic Semiconductor. All rights reserved. +// +// +//#import +//#import +#include +#include + +#include "dfu_operations_details.h" +#include "dfu_utility.h" +#include "file_operations.h" +#include "metawear/core/metawearboard.h" +//#import "MBL_BLEOperations.h" + + + +// +// +//@class MBL_DFUOperations; +// +////define protocol for the delegate +//@protocol MBL_DFUOperationsDelegate +// +////define protocol functions that can be used in any class using this delegate +//-(void)onDeviceConnected:(CBPeripheral *)peripheral; +//-(void)onDeviceDisconnected:(CBPeripheral *)peripheral; +//-(void)onDFUStarted; +//-(void)onDFUCancelled; +//-(void)onSoftDeviceUploadStarted; +//-(void)onBootloaderUploadStarted; +//-(void)onSoftDeviceUploadCompleted; +//-(void)onBootloaderUploadCompleted; +//-(void)onTransferPercentage:(int)percentage; +//-(void)onSuccessfulFileTranferred; +//-(void)onError:(NSString *)errorMessage; +// +//@end + +class DfuOperations : public FileOperationsDelegate { + //@property (nonatomic) CBPeripheral *bluetoothPeripheral; + //@property (nonatomic) CBCharacteristic *dfuPacketCharacteristic; + //@property (nonatomic) CBCharacteristic *dfuControlPointCharacteristic; + // + //@property (nonatomic) MBL_BLEOperations *bleOperations; + std::unique_ptr dfuRequests; + std::unique_ptr fileRequests; + //@property (nonatomic) MBL_FileOperations *fileRequests2; + //@property (nonatomic) MBL_DfuFirmwareTypes dfuFirmwareType; + //@property (nonatomic) NSUInteger binFileSize; + //@property (nonatomic) NSUInteger uploadTimeInSeconds; + //@property (nonatomic) NSURL *firmwareFile; + struct DFUResponse dfuResponse; + + MblMwDfuDelegate dfuDelegate; + + bool isVersionCharacteristicExist; + bool isPerformedOldDFU; + + void setDFUResponseStruct(const uint8_t *data, uint8_t len); + void processRequestedCode(); + void processStartDFUResponseStatus(); + void processReceiveFirmwareResponseStatus(); + void processValidateFirmwareResponseStatus(); + void processInitPacketResponseStatus(); + + void processPacketNotification(); + + void startSendingFile(); + + // FileOperationsDelegate + void onTransferPercentage(int32_t); + void onAllPacketsTranferred(); + void onFileOpened(size_t); + void onError(const std::string &); + +public: + DfuOperations(const MblMwMetaWearBoard* board, const MblMwDfuDelegate *delegate); + virtual ~DfuOperations(); + + //define public methods + //void setCentralManager:(CBCentralManager *)manager; + //void connectDevice:(CBPeripheral *)peripheral; + //void performDFUOnFile:(NSURL *)firmwareURL firmwareType:(MBL_DfuFirmwareTypes)firmwareType; + //void performDFUOnFiles:(NSURL *)softdeviceURL bootloaderURL:(NSURL *)bootloaderURL firmwareType:(MBL_DfuFirmwareTypes)firmwareType; + void perfromDFUOnZipFile(const char *zipFilename); + void performOldDFUOnFile(const char *firmwareFilename); + + void cancelDFU(); + + + void processDFUResponse(const uint8_t *data, uint8_t len); +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.cpp new file mode 100644 index 0000000..d42ba61 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.cpp @@ -0,0 +1,100 @@ +#include "dfu_operations_details.h" + +#include +#include + +#include "dfu_utility.h" +#include "metawear/core/cpp/metawearboard_def.h" + +DFUOperationsDetails::DFUOperationsDetails(const MblMwMetaWearBoard* board) : bootloaderBoard(board) { +} + +void DFUOperationsDetails::startDFU(MblDfuFirmwareTypes firmwareType) { + dfuFirmwareType = firmwareType; + uint8_t value[] = { START_DFU_REQUEST, (uint8_t)firmwareType }; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, value, sizeof(value)/sizeof(value[0])); +} + +void DFUOperationsDetails::startOldDFU() { + uint8_t value[] = { START_DFU_REQUEST }; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, value, sizeof(value)/sizeof(value[0])); +} + +void DFUOperationsDetails::writeFileSize(uint32_t firmwareSize) { + uint32_t fileSizeCollection[3]; + switch (dfuFirmwareType) { + case SOFTDEVICE: + fileSizeCollection[0] = firmwareSize; + fileSizeCollection[1] = 0; + fileSizeCollection[2] = 0; + break; + case BOOTLOADER: + fileSizeCollection[0] = 0; + fileSizeCollection[1] = firmwareSize; + fileSizeCollection[2] = 0; + break; + case APPLICATION: + fileSizeCollection[0] = 0; + fileSizeCollection[1] = 0; + fileSizeCollection[2] = firmwareSize; + break; + default: + break; + } + bootloaderBoard->write_gatt_char(&DFU_PACKET_CHAR, MBL_MW_GATT_CHAR_WRITE_WITHOUT_RESPONSE, (uint8_t *)&fileSizeCollection, sizeof(fileSizeCollection)); +} + +void DFUOperationsDetails::writeFileSizeForOldDFU(uint32_t firmwareSize) { + bootloaderBoard->write_gatt_char(&DFU_PACKET_CHAR, MBL_MW_GATT_CHAR_WRITE_WITHOUT_RESPONSE, (uint8_t *)&firmwareSize, sizeof(firmwareSize)); +} + +void DFUOperationsDetails::enablePacketNotification() { + uint8_t value[] = { PACKET_RECEIPT_NOTIFICATION_REQUEST, (uint8_t)MBL_PACKETS_NOTIFICATION_INTERVAL, 0} ; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, value, sizeof(value)/sizeof(value[0])); +} +void DFUOperationsDetails::receiveFirmwareImage() { + uint8_t value[] = { RECEIVE_FIRMWARE_IMAGE_REQUEST }; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, value, sizeof(value)/sizeof(value[0])); +} + +void DFUOperationsDetails::validateFirmware() { + uint8_t value[] = { VALIDATE_FIRMWARE_REQUEST }; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, value, sizeof(value)/sizeof(value[0])); +} + +void DFUOperationsDetails::activateAndReset() { + uint8_t value[] = { ACTIVATE_AND_RESET_REQUEST }; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, value, sizeof(value)/sizeof(value[0])); +} + +void DFUOperationsDetails::resetSystem() { + uint8_t value[] = { RESET_SYSTEM }; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, value, sizeof(value)/sizeof(value[0])); +} + +void DFUOperationsDetails::sendInitPacket(uint8_t *fileData, int fileDataLength) { + int numberOfPackets = std::ceil((double)fileDataLength / (double)MBL_PACKET_SIZE); + int bytesInLastPacket = fileDataLength % 20; + //NSLog(@"metaDataFile length: %lu and number of packets: %d",(unsigned long)[fileData length], numberOfPackets); + + //send initPacket with parameter value set to Receive Init Packet [0] to dfu Control Point Characteristic + uint8_t initPacketStart[] = {INITIALIZE_DFU_PARAMETERS_REQUEST, START_INIT_PACKET}; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, (uint8_t *)&initPacketStart, sizeof(initPacketStart)); + + // send init Packet data to dfu Packet Characteristic + // for longer .dat file the data need to be chopped into 20 bytes + for (int index = 0; index < numberOfPackets-1; index++) { + //chopping data into 20 bytes packet + uint8_t *packetData = &fileData[index * MBL_PACKET_SIZE]; + //writing 20 bytes packet to peripheral + bootloaderBoard->write_gatt_char(&DFU_PACKET_CHAR, MBL_MW_GATT_CHAR_WRITE_WITHOUT_RESPONSE, packetData, MBL_PACKET_SIZE); + } + //chopping data for last packet that can be less than 20 bytes + uint8_t *packetData = &fileData[(numberOfPackets - 1) * MBL_PACKET_SIZE]; + //writing last packet + bootloaderBoard->write_gatt_char(&DFU_PACKET_CHAR, MBL_MW_GATT_CHAR_WRITE_WITHOUT_RESPONSE, packetData, bytesInLastPacket); + + //send initPacket with parameter value set to Init Packet Complete [1] to dfu Control Point Characteristic + uint8_t initPacketEnd[] = { INITIALIZE_DFU_PARAMETERS_REQUEST, END_INIT_PACKET }; + bootloaderBoard->write_gatt_char(&DFU_CONTROL_POINT_CHAR, MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE, (uint8_t *)&initPacketEnd, sizeof(initPacketEnd)); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.h new file mode 100644 index 0000000..8fe9f18 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "metawear/core/metawearboard_fwd.h" +#include "dfu_utility.h" + +class DFUOperationsDetails { + //@property (nonatomic) MBL_DfuFirmwareTypes dfuFirmwareType; + const MblMwMetaWearBoard* bootloaderBoard; + MblDfuFirmwareTypes dfuFirmwareType; + +public: + DFUOperationsDetails(const MblMwMetaWearBoard* board); + + //void enableNotification(); + void startDFU(MblDfuFirmwareTypes firmwareType); + void startOldDFU(); + void writeFileSize(uint32_t firmwareSize); + //void writeFilesSizes:(uint32_t)softdeviceSize bootloaderSize:(uint32_t)bootloaderSize; + void writeFileSizeForOldDFU(uint32_t firmwareSize); + void enablePacketNotification(); + void receiveFirmwareImage(); + void validateFirmware(); + void activateAndReset(); + void resetSystem(); + + //Init Packet is included in new DFU in SDK 7.0 + void sendInitPacket(uint8_t *fileData, int fileDataLength); +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.cpp new file mode 100644 index 0000000..f2d5b44 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.cpp @@ -0,0 +1,4 @@ +#include "dfu_utility.h" + +int MBL_PACKETS_NOTIFICATION_INTERVAL = 10; +int const MBL_PACKET_SIZE = 20; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.h new file mode 100644 index 0000000..d426d40 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.h @@ -0,0 +1,90 @@ +#pragma once + +// +// MBL_Utility.h +// nRFDeviceFirmwareUpdate +// +// Created by Nordic Semiconductor on 22/05/14. +// Copyright (c) 2014 Nordic Semiconductor. All rights reserved. +// + +#include + +//#import + +//@interface MBL_Utility : NSObject + +//extern NSString * const MBL_dfuServiceUUIDString; +//extern NSString * const MBL_dfuControlPointCharacteristicUUIDString; +//extern NSString * const MBL_dfuPacketCharacteristicUUIDString; + +//extern NSString* const MBL_FIRMWARE_TYPE_SOFTDEVICE; +//extern NSString* const MBL_FIRMWARE_TYPE_BOOTLOADER; +//extern NSString* const MBL_FIRMWARE_TYPE_APPLICATION; +//extern NSString* const MBL_FIRMWARE_TYPE_BOTH_SOFTDEVICE_BOOTLOADER; +// +// + +extern int MBL_PACKETS_NOTIFICATION_INTERVAL; +extern int const MBL_PACKET_SIZE; + +struct DFUResponse +{ + uint8_t responseCode; + uint8_t requestedCode; + uint8_t responseStatus; +}; + +//typedef enum { +// HEX, +// ZIP +//} MblDfuFileExtension; + +typedef enum { + START_INIT_PACKET = 0x00, + END_INIT_PACKET = 0x01 +} MblInitPacketParam; + +/** + * Enumeration of DFU opcodes + */ +typedef enum { + START_DFU_REQUEST = 0x01, + INITIALIZE_DFU_PARAMETERS_REQUEST = 0x02, + RECEIVE_FIRMWARE_IMAGE_REQUEST = 0x03, + VALIDATE_FIRMWARE_REQUEST = 0x04, + ACTIVATE_AND_RESET_REQUEST = 0x05, + RESET_SYSTEM = 0x06, + PACKET_RECEIPT_NOTIFICATION_REQUEST = 0x08, + RESPONSE_CODE = 0x10, + PACKET_RECEIPT_NOTIFICATION_RESPONSE = 0x11 +} MblDfuOperations; + +/** + * Enumeration of DFU status codes + */ +typedef enum { + OPERATION_SUCCESSFUL_RESPONSE = 0x01, + OPERATION_INVALID_RESPONSE = 0x02, + OPERATION_NOT_SUPPORTED_RESPONSE = 0x03, + DATA_SIZE_EXCEEDS_LIMIT_RESPONSE = 0x04, + CRC_ERROR_RESPONSE = 0x05, + OPERATION_FAILED_RESPONSE = 0x06 +} MblDfuOperationStatus; + +/** + * Enumeration of DFU firmware types + */ +typedef enum { + SOFTDEVICE = 0x01, + BOOTLOADER = 0x02, + SOFTDEVICE_AND_BOOTLOADER = 0x03, + APPLICATION = 0x04 +} MblDfuFirmwareTypes; + +//+ (NSArray *) getFirmwareTypes; +//+ (NSString *) stringFileExtension:(MBL_enumFileExtension)fileExtension; +//+ (NSString *) getDFUHelpText; +//+ (NSString *) getEmptyUserFilesText; +//+ (NSString *) getDFUAppFileHelpText; + diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.cpp new file mode 100644 index 0000000..d6626ca --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.cpp @@ -0,0 +1,171 @@ +#include +#include + +#include "file_operations.h" +#include "dfu_utility.h" + +#include "metawear/core/cpp/metawearboard_def.h" + +#include "miniz.h" +#include "json.hpp" + +FileOperationsDelegate::~FileOperationsDelegate() { + +} + +FileOperations::FileOperations(FileOperationsDelegate &fileDelegate, const MblMwMetaWearBoard* board) : binFile(0), fileDelegate(fileDelegate), bootloaderBoard(board), metaDataFile(0) { + +} + +FileOperations::~FileOperations() { + if (binFile) { + mz_free(binFile); + } + if (metaDataFile) { + mz_free(metaDataFile); + } +} + +void FileOperations::openFile(const char* filename) +{ + std::ifstream file; + file.exceptions(std::ifstream::badbit | std::ifstream::failbit | std::ifstream::eofbit); + //Need to use binary mode; otherwise CRLF line endings count as 2 for + //`length` calculation but only 1 for `file.read` (on some platforms), + //and we get undefined behaviour when trying to read `length` characters. + file.open(filename, std::ifstream::in | std::ifstream::binary); + file.seekg(0, std::ios::end); + std::streampos length(file.tellg()); + if (length) { + file.seekg(0, std::ios::beg); + binFileSize = static_cast(length); + binFile = static_cast(malloc(binFileSize)); + // Load all the data to our local vector + file.read((char *)binFile, binFileSize); + + // Compute how we need to slice up the file into BLE sized chunks + numberOfPackets = std::ceil((double)binFileSize / (double)MBL_PACKET_SIZE); + bytesInLastPacket = binFileSize % MBL_PACKET_SIZE; + if (bytesInLastPacket == 0) { + bytesInLastPacket = MBL_PACKET_SIZE; + } + writingPacketNumber = 0; + prevPercentage = -1; + // Let the delegate know we opened it! + fileDelegate.onFileOpened(binFileSize); + } else { + fileDelegate.onError("0 length file"); + } +} + +void FileOperations::writeNextPacket() +{ + int percentage = 0; + for (int index = 0; index < MBL_PACKETS_NOTIFICATION_INTERVAL; index++) { + if (writingPacketNumber > numberOfPackets - 2) { + //NSLog(@"writing last packet"); + uint8_t *nextPacketData = &binFile[writingPacketNumber * MBL_PACKET_SIZE]; + //NSLog(@"writing packet number %d ...",self.writingPacketNumber+1); + //NSLog(@"packet data: %@",nextPacketData); + bootloaderBoard->write_gatt_char(&DFU_PACKET_CHAR, MBL_MW_GATT_CHAR_WRITE_WITHOUT_RESPONSE, nextPacketData, bytesInLastPacket); + writingPacketNumber++; + fileDelegate.onTransferPercentage(100); + fileDelegate.onAllPacketsTranferred(); + break; + } + uint8_t *nextPacketData = &binFile[writingPacketNumber * MBL_PACKET_SIZE]; + //NSLog(@"writing packet number %d ...",self.writingPacketNumber+1); + //NSLog(@"packet data: %@",nextPacketData); + bootloaderBoard->write_gatt_char(&DFU_PACKET_CHAR, MBL_MW_GATT_CHAR_WRITE_WITHOUT_RESPONSE, nextPacketData, MBL_PACKET_SIZE); + percentage = (((double)(writingPacketNumber * 20) / (double)(binFileSize)) * 100); + if (percentage != prevPercentage) { + fileDelegate.onTransferPercentage(percentage); + prevPercentage = percentage; + } + writingPacketNumber++; + } +} + +void FileOperations::openZip(const char *filename) +{ + int i; + mz_bool status; + size_t uncomp_size; + mz_zip_archive zip_archive = { 0 }; + void *p; + std::string metadataFilename, firmwareFilename; + + status = mz_zip_reader_init_file(&zip_archive, filename, MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY); + if (!status) { + fileDelegate.onError("mz_zip_reader_init_file() failed!"); + return; + } + + for (i = 0; i < (int)mz_zip_reader_get_num_files(&zip_archive); i++) { + mz_zip_archive_file_stat file_stat; + if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) { + fileDelegate.onError("mz_zip_reader_file_stat() failed!"); + mz_zip_reader_end(&zip_archive); + return; + } + if (std::string(file_stat.m_filename) == "manifest.json") { + // Try to extract the manifest to the heap + p = mz_zip_reader_extract_file_to_heap(&zip_archive, file_stat.m_filename, &uncomp_size, 0); + if (!p) { + fileDelegate.onError("mz_zip_reader_extract_file_to_heap() failed!"); + mz_zip_reader_end(&zip_archive); + return; + } + // Pull out the firmware and data filenames + auto manifest = nlohmann::json::parse(std::string((const char *)p, uncomp_size)); + auto it = manifest.find("manifest"); + if (it != manifest.end()) { + auto it1 = it->find("application"); + if (it1 != it->end()) { + auto it2 = it1->find("bin_file"); + if (it2 != it1->end()) { + firmwareFilename = *it2; + } + auto it3 = it1->find("dat_file"); + if (it3 != it1->end()) { + metadataFilename = *it3; + } + } + } + // We're done. + mz_free(p); + } + } + + if (metadataFilename.empty() || firmwareFilename.empty()) { + fileDelegate.onError("error parsing manifest"); + return; + } + + // Open the Metadata file + metaDataFile = static_cast(mz_zip_reader_extract_file_to_heap(&zip_archive, metadataFilename.c_str(), &metaDataFileSize, 0)); + if (!metaDataFile) { + fileDelegate.onError("mz_zip_reader_extract_file_to_heap() failed!"); + mz_zip_reader_end(&zip_archive); + return; + } + + // Process the firmware file + binFile = static_cast(mz_zip_reader_extract_file_to_heap(&zip_archive, firmwareFilename.c_str(), &binFileSize, 0)); + if (!binFile) { + fileDelegate.onError("mz_zip_reader_extract_file_to_heap() failed!"); + mz_zip_reader_end(&zip_archive); + return; + } + // Compute how we need to slice up the file into BLE sized chunks + numberOfPackets = std::ceil((double)binFileSize / (double)MBL_PACKET_SIZE); + bytesInLastPacket = binFileSize % MBL_PACKET_SIZE; + if (bytesInLastPacket == 0) { + bytesInLastPacket = MBL_PACKET_SIZE; + } + writingPacketNumber = 0; + // Let the delegate know we opened it! + fileDelegate.onFileOpened(binFileSize); + + mz_zip_reader_end(&zip_archive); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.h new file mode 100644 index 0000000..e2fa4fb --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +struct FileOperationsDelegate { + virtual ~FileOperationsDelegate() = 0; + // define callback interface functions + virtual void onTransferPercentage(int) = 0; + virtual void onAllPacketsTranferred() = 0; + virtual void onFileOpened(size_t) = 0; + virtual void onError(const std::string &) = 0; +}; + +class FileOperations { + uint8_t *binFile; + int bytesInLastPacket; + int prevPercentage; + + FileOperationsDelegate &fileDelegate; + const MblMwMetaWearBoard* bootloaderBoard; +public: + size_t binFileSize; + int numberOfPackets; + int writingPacketNumber; + + uint8_t *metaDataFile; + size_t metaDataFileSize; + + FileOperations(FileOperationsDelegate &fileDelegate, const MblMwMetaWearBoard* board); + ~FileOperations(); + + void openFile(const char* filename); + void writeNextPacket(); + + void openZip(const char *filename); +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/json.hpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/json.hpp new file mode 100644 index 0000000..35bdd29 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/json.hpp @@ -0,0 +1,10036 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 2.0.1 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2013-2016 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + + +/*! +@brief unnamed namespace with internal helper functions +@since version 1.0.0 +*/ +namespace +{ +/*! +@brief Helper to determine whether there's a key_type for T. +@sa http://stackoverflow.com/a/7728728/266378 +*/ +template +struct has_mapped_type +{ + private: + template static char test(typename C::mapped_type*); + template static char (&test(...))[2]; + public: + static constexpr bool value = sizeof(test(0)) == 1; +}; + +/*! +@brief helper class to create locales with decimal point +@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 +*/ +class DecimalSeparator : public std::numpunct +{ + protected: + char do_decimal_point() const + { + return '.'; + } +}; + +} + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null value. + - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): + JSON values have + [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the class + has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](http://en.cppreference.com/w/cpp/concept/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@internal +@note ObjectType trick from http://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange +Format](http://rfc7159.net/rfc7159) + +@since version 1.0.0 + +@nosubgrouping +*/ +template < + template class ObjectType = std::map, + template class ArrayType = std::vector, + class StringType = std::string, + class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator + > +class basic_json +{ + private: + /// workaround type for MSVC + using basic_json_t = basic_json; + + public: + // forward declarations + template class json_reverse_iterator; + class json_pointer; + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + class iterator; + /// a const iterator for a basic_json container + class const_iterator; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// @{ + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType, + AllocatorType>>; + + /*! + @brief a type for an array + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### String comparison + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], this + class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /// @} + + + /////////////////////////// + // JSON type enumeration // + /////////////////////////// + + /*! + @brief the JSON type enumeration + + This enumeration collects the different JSON types. It is internally used + to distinguish the stored values, and the functions @ref is_null(), @ref + is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref + is_number(), and @ref is_discarded() rely on it. + + @since version 1.0.0 + */ + enum class value_t : uint8_t + { + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function + }; + + + private: + + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) + { + AllocatorType alloc; + auto deleter = [&](T * object) + { + alloc.deallocate(object, 1); + }; + std::unique_ptr object(alloc.allocate(1), deleter); + alloc.construct(object.get(), std::forward(args)...); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + default: + { + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + }; + + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief JSON callback events + + This enumeration lists the parser events that can trigger calling a + callback function of type @ref parser_callback_t during parsing. + + @since version 1.0.0 + */ + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse(std::istream&, parser_callback_t) or + @ref parse(const string_t&, parser_callback_t), it is called on certain + events (passed as @ref parse_event_t via parameter @a event) with a set + recursion depth @a depth and context JSON value @a parsed. The return + value of the callback function is a boolean indicating whether the element + that emitted the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse(std::istream&, parser_callback_t) or + @ref parse(const string_t&, parser_callback_t) for examples + + @since version 1.0.0 + */ + using parser_callback_t = std::function; + + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] value_type the type of the value to create + + @complexity Constant. + + @throw std::bad_alloc if allocation for object, array, or string value + fails + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + @sa @ref basic_json(boolean_t value) -- create a boolean value + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const object_t&) -- create a object value + @sa @ref basic_json(const array_t&) -- create a array value + @sa @ref basic_json(const number_float_t) -- create a number + (floating-point) value + @sa @ref basic_json(const number_integer_t) -- create a number (integer) + value + @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned) + value + + @since version 1.0.0 + */ + basic_json(const value_t value_type) + : m_type(value_type), m_value(value_type) + {} + + /*! + @brief create a null object (implicitly) + + Create a `null` JSON value. This is the implicit version of the `null` + value constructor as it takes no parameters. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - As postcondition, it holds: `basic_json().empty() == true`. + + @liveexample{The following code shows the constructor for a `null` JSON + value.,basic_json} + + @sa @ref basic_json(std::nullptr_t) -- create a `null` value + + @since version 1.0.0 + */ + basic_json() = default; + + /*! + @brief create a null object (explicitly) + + Create a `null` JSON value. This is the explicitly version of the `null` + value constructor as it takes a null pointer as parameter. It allows to + create `null` values by explicitly assigning a `nullptr` to a JSON value. + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with null pointer + parameter.,basic_json__nullptr_t} + + @sa @ref basic_json() -- default constructor (implicitly creating a `null` + value) + + @since version 1.0.0 + */ + basic_json(std::nullptr_t) noexcept + : basic_json(value_t::null) + {} + + /*! + @brief create an object (explicit) + + Create an object JSON value with a given content. + + @param[in] val a value for the object + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for object value fails + + @liveexample{The following code shows the constructor with an @ref + object_t parameter.,basic_json__object_t} + + @sa @ref basic_json(const CompatibleObjectType&) -- create an object value + from a compatible STL container + + @since version 1.0.0 + */ + basic_json(const object_t& val) + : m_type(value_t::object), m_value(val) + {} + + /*! + @brief create an object (implicit) + + Create an object JSON value with a given content. This constructor allows + any type @a CompatibleObjectType that can be used to construct values of + type @ref object_t. + + @tparam CompatibleObjectType An object type whose `key_type` and + `value_type` is compatible to @ref object_t. Examples include `std::map`, + `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with + a `key_type` of `std::string`, and a `value_type` from which a @ref + basic_json value can be constructed. + + @param[in] val a value for the object + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for object value fails + + @liveexample{The following code shows the constructor with several + compatible object type parameters.,basic_json__CompatibleObjectType} + + @sa @ref basic_json(const object_t&) -- create an object value + + @since version 1.0.0 + */ + template ::value and + std::is_constructible::value, int>::type + = 0> + basic_json(const CompatibleObjectType& val) + : m_type(value_t::object) + { + using std::begin; + using std::end; + m_value.object = create(begin(val), end(val)); + } + + /*! + @brief create an array (explicit) + + Create an array JSON value with a given content. + + @param[in] val a value for the array + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for array value fails + + @liveexample{The following code shows the constructor with an @ref array_t + parameter.,basic_json__array_t} + + @sa @ref basic_json(const CompatibleArrayType&) -- create an array value + from a compatible STL containers + + @since version 1.0.0 + */ + basic_json(const array_t& val) + : m_type(value_t::array), m_value(val) + {} + + /*! + @brief create an array (implicit) + + Create an array JSON value with a given content. This constructor allows + any type @a CompatibleArrayType that can be used to construct values of + type @ref array_t. + + @tparam CompatibleArrayType An object type whose `value_type` is + compatible to @ref array_t. Examples include `std::vector`, `std::deque`, + `std::list`, `std::forward_list`, `std::array`, `std::set`, + `std::unordered_set`, `std::multiset`, and `unordered_multiset` with a + `value_type` from which a @ref basic_json value can be constructed. + + @param[in] val a value for the array + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for array value fails + + @liveexample{The following code shows the constructor with several + compatible array type parameters.,basic_json__CompatibleArrayType} + + @sa @ref basic_json(const array_t&) -- create an array value + + @since version 1.0.0 + */ + template ::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + std::is_constructible::value, int>::type + = 0> + basic_json(const CompatibleArrayType& val) + : m_type(value_t::array) + { + using std::begin; + using std::end; + m_value.array = create(begin(val), end(val)); + } + + /*! + @brief create a string (explicit) + + Create an string JSON value with a given content. + + @param[in] val a value for the string + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the constructor with an @ref + string_t parameter.,basic_json__string_t} + + @sa @ref basic_json(const typename string_t::value_type*) -- create a + string value from a character pointer + @sa @ref basic_json(const CompatibleStringType&) -- create a string value + from a compatible string container + + @since version 1.0.0 + */ + basic_json(const string_t& val) + : m_type(value_t::string), m_value(val) + {} + + /*! + @brief create a string (explicit) + + Create a string JSON value with a given content. + + @param[in] val a literal value for the string + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the constructor with string literal + parameter.,basic_json__string_t_value_type} + + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const CompatibleStringType&) -- create a string value + from a compatible string container + + @since version 1.0.0 + */ + basic_json(const typename string_t::value_type* val) + : basic_json(string_t(val)) + {} + + /*! + @brief create a string (implicit) + + Create a string JSON value with a given content. + + @param[in] val a value for the string + + @tparam CompatibleStringType an string type which is compatible to @ref + string_t, for instance `std::string`. + + @complexity Linear in the size of the passed @a val. + + @throw std::bad_alloc if allocation for string value fails + + @liveexample{The following code shows the construction of a string value + from a compatible type.,basic_json__CompatibleStringType} + + @sa @ref basic_json(const string_t&) -- create a string value + @sa @ref basic_json(const typename string_t::value_type*) -- create a + string value from a character pointer + + @since version 1.0.0 + */ + template ::value, int>::type + = 0> + basic_json(const CompatibleStringType& val) + : basic_json(string_t(val)) + {} + + /*! + @brief create a boolean (explicit) + + Creates a JSON boolean type from a given value. + + @param[in] val a boolean value to store + + @complexity Constant. + + @liveexample{The example below demonstrates boolean + values.,basic_json__boolean_t} + + @since version 1.0.0 + */ + basic_json(boolean_t val) noexcept + : m_type(value_t::boolean), m_value(val) + {} + + /*! + @brief create an integer number (explicit) + + Create an integer number JSON value with a given content. + + @tparam T A helper type to remove this function via SFINAE in case @ref + number_integer_t is the same as `int`. In this case, this constructor + would have the same signature as @ref basic_json(const int value). Note + the helper type @a T is not visible in this constructor's interface. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @liveexample{The example below shows the construction of an integer + number value.,basic_json__number_integer_t} + + @sa @ref basic_json(const int) -- create a number value (integer) + @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number + value (integer) from a compatible number type + + @since version 1.0.0 + */ + template::value) + and std::is_same::value + , int>::type + = 0> + basic_json(const number_integer_t val) noexcept + : m_type(value_t::number_integer), m_value(val) + {} + + /*! + @brief create an integer number from an enum type (explicit) + + Create an integer number JSON value with a given content. + + @param[in] val an integer to create a JSON number from + + @note This constructor allows to pass enums directly to a constructor. As + C++ has no way of specifying the type of an anonymous enum explicitly, we + can only rely on the fact that such values implicitly convert to int. As + int may already be the same type of number_integer_t, we may need to + switch off the constructor @ref basic_json(const number_integer_t). + + @complexity Constant. + + @liveexample{The example below shows the construction of an integer + number value from an anonymous enum.,basic_json__const_int} + + @sa @ref basic_json(const number_integer_t) -- create a number value + (integer) + @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number + value (integer) from a compatible number type + + @since version 1.0.0 + */ + basic_json(const int val) noexcept + : m_type(value_t::number_integer), + m_value(static_cast(val)) + {} + + /*! + @brief create an integer number (implicit) + + Create an integer number JSON value with a given content. This constructor + allows any type @a CompatibleNumberIntegerType that can be used to + construct values of type @ref number_integer_t. + + @tparam CompatibleNumberIntegerType An integer type which is compatible to + @ref number_integer_t. Examples include the types `int`, `int32_t`, + `long`, and `short`. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @liveexample{The example below shows the construction of several integer + number values from compatible + types.,basic_json__CompatibleIntegerNumberType} + + @sa @ref basic_json(const number_integer_t) -- create a number value + (integer) + @sa @ref basic_json(const int) -- create a number value (integer) + + @since version 1.0.0 + */ + template::value and + std::numeric_limits::is_integer and + std::numeric_limits::is_signed, + CompatibleNumberIntegerType>::type + = 0> + basic_json(const CompatibleNumberIntegerType val) noexcept + : m_type(value_t::number_integer), + m_value(static_cast(val)) + {} + + /*! + @brief create an unsigned integer number (explicit) + + Create an unsigned integer number JSON value with a given content. + + @tparam T helper type to compare number_unsigned_t and unsigned int + (not visible in) the interface. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number + value (unsigned integer) from a compatible number type + + @since version 2.0.0 + */ + template::value) + and std::is_same::value + , int>::type + = 0> + basic_json(const number_unsigned_t val) noexcept + : m_type(value_t::number_unsigned), m_value(val) + {} + + /*! + @brief create an unsigned number (implicit) + + Create an unsigned number JSON value with a given content. This + constructor allows any type @a CompatibleNumberUnsignedType that can be + used to construct values of type @ref number_unsigned_t. + + @tparam CompatibleNumberUnsignedType An integer type which is compatible + to @ref number_unsigned_t. Examples may include the types `unsigned int`, + `uint32_t`, or `unsigned short`. + + @param[in] val an unsigned integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const number_unsigned_t) -- create a number value + (unsigned) + + @since version 2.0.0 + */ + template ::value and + std::numeric_limits::is_integer and + not std::numeric_limits::is_signed, + CompatibleNumberUnsignedType>::type + = 0> + basic_json(const CompatibleNumberUnsignedType val) noexcept + : m_type(value_t::number_unsigned), + m_value(static_cast(val)) + {} + + /*! + @brief create a floating-point number (explicit) + + Create a floating-point number JSON value with a given content. + + @param[in] val a floating-point value to create a JSON number from + + @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 + disallows NaN values: + > Numeric values that cannot be represented in the grammar below (such as + > Infinity and NaN) are not permitted. + In case the parameter @a val is not a number, a JSON null value is + created instead. + + @complexity Constant. + + @liveexample{The following example creates several floating-point + values.,basic_json__number_float_t} + + @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number + value (floating-point) from a compatible number type + + @since version 1.0.0 + */ + basic_json(const number_float_t val) noexcept + : m_type(value_t::number_float), m_value(val) + { + // replace infinity and NAN by null + if (not std::isfinite(val)) + { + m_type = value_t::null; + m_value = json_value(); + } + } + + /*! + @brief create an floating-point number (implicit) + + Create an floating-point number JSON value with a given content. This + constructor allows any type @a CompatibleNumberFloatType that can be used + to construct values of type @ref number_float_t. + + @tparam CompatibleNumberFloatType A floating-point type which is + compatible to @ref number_float_t. Examples may include the types `float` + or `double`. + + @param[in] val a floating-point to create a JSON number from + + @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 + disallows NaN values: + > Numeric values that cannot be represented in the grammar below (such as + > Infinity and NaN) are not permitted. + In case the parameter @a val is not a number, a JSON null value is + created instead. + + @complexity Constant. + + @liveexample{The example below shows the construction of several + floating-point number values from compatible + types.,basic_json__CompatibleNumberFloatType} + + @sa @ref basic_json(const number_float_t) -- create a number value + (floating-point) + + @since version 1.0.0 + */ + template::value and + std::is_floating_point::value>::type + > + basic_json(const CompatibleNumberFloatType val) noexcept + : basic_json(number_float_t(val)) + {} + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are treated + as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has now way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them as + an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(std::initializer_list) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(std::initializer_list) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(std::initializer_list) and + @ref object(std::initializer_list). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw std::domain_error if @a type_deduction is `false`, @a manual_type + is `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string; example: `"cannot create object from + initializer list"` + + @complexity Linear in the size of the initializer list @a init. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(std::initializer_list init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // the initializer list could describe an object + bool is_an_object = true; + + // check if each element is an array with two elements whose first + // element is a string + for (const auto& element : init) + { + if (not element.is_array() or element.size() != 2 + or not element[0].is_string()) + { + // we found an element that makes it impossible to use the + // initializer list as object + is_an_object = false; + break; + } + } + + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (manual_type == value_t::object and not is_an_object) + { + throw std::domain_error("cannot create object from initializer list"); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + assert(m_value.object != nullptr); + + for (auto& element : init) + { + m_value.object->emplace(*(element[0].m_value.string), element[1]); + } + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init); + } + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(std::initializer_list, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + static basic_json array(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(std::initializer_list), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(std::initializer_list, bool, + value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw std::domain_error if @a init is not a pair whose first elements are + strings; thrown by + @ref basic_json(std::initializer_list, bool, value_t) + + @complexity Linear in the size of @a init. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + static basic_json object(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. As postcondition, + `std::distance(begin(),end()) == cnt` holds. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @complexity Linear in @a cnt. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of primitive types (number, boolean, or string), @a first must + be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, std::out_of_range is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector`. + - In case of a null type, std::domain_error is thrown. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @throw std::domain_error if iterators are not compatible; that is, do not + belong to the same JSON value; example: `"iterators are not compatible"` + @throw std::out_of_range if iterators are for a primitive type (number, + boolean, or string) where an out of range error can be detected easily; + example: `"iterators out of range"` + @throw std::bad_alloc if allocation for object, array, or string fails + @throw std::domain_error if called with a null value; example: `"cannot + use construct with iterators from null"` + + @complexity Linear in distance between @a first and @a last. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type) + { + // make sure iterator fits the current value + if (first.m_object != last.m_object) + { + throw std::domain_error("iterators are not compatible"); + } + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + throw std::out_of_range("iterators out of range"); + } + break; + } + + default: + { + break; + } + } + + switch (m_type) + { + case value_t::number_integer: + { + assert(first.m_object != nullptr); + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + assert(first.m_object != nullptr); + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + assert(first.m_object != nullptr); + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + assert(first.m_object != nullptr); + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + assert(first.m_object != nullptr); + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); + break; + } + + default: + { + assert(first.m_object != nullptr); + throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); + } + } + } + + /*! + @brief construct a JSON value given an input stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates constructing a JSON value from + a `std::stringstream` with and without callback + function.,basic_json__istream} + + @since version 2.0.0 + */ + explicit basic_json(std::istream& i, parser_callback_t cb = nullptr) + { + *this = parser(i, cb).parse(); + } + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @complexity Linear in the size of @a other. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @throw std::bad_alloc if allocation for object, array, or string fails. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + switch (m_type) + { + case value_t::object: + { + assert(other.m_value.object != nullptr); + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + assert(other.m_value.array != nullptr); + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + assert(other.m_value.string != nullptr); + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + { + break; + } + } + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post @a other is a JSON null value + + @complexity Constant. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the swap() member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + reference& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() + { + switch (m_type) + { + case value_t::object: + { + AllocatorType alloc; + alloc.destroy(m_value.object); + alloc.deallocate(m_value.object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + alloc.destroy(m_value.array); + alloc.deallocate(m_value.array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + break; + } + + default: + { + // all other types need no specific destructor + break; + } + } + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's @p json.dumps() function, and currently supports its @p indent + parameter. + + @param[in] indent if indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + 0 will only insert newlines. -1 (the default) selects the most compact + representation + + @return string containing the serialization of the JSON value + + @complexity Linear. + + @liveexample{The following example shows the effect of different @a indent + parameters to the result of the serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0 + */ + string_t dump(const int indent = -1) const + { + std::stringstream ss; + // fix locale problems + ss.imbue(std::locale(std::locale(), new DecimalSeparator)); + + if (indent >= 0) + { + dump(ss, true, static_cast(indent)); + } + else + { + dump(ss, false, 0); + } + + return ss.str(); + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true iff the JSON type is primitive (string, number, + boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } + + /*! + @brief return whether type is structured + + This function returns true iff the JSON type is structured (array or + object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() or is_object(); + } + + /*! + @brief return whether value is null + + This function returns true iff the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return m_type == value_t::null; + } + + /*! + @brief return whether value is a boolean + + This function returns true iff the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } + + /*! + @brief return whether value is a number + + This function returns true iff the JSON value is a number. This includes + both integer and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true iff the JSON value is an integer or unsigned + integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer or m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true iff the JSON value is an unsigned integer + number. This excludes floating-point and (signed) integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is a floating-point number + + This function returns true iff the JSON value is a floating-point number. + This excludes integer and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } + + /*! + @brief return whether value is an object + + This function returns true iff the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return m_type == value_t::object; + } + + /*! + @brief return whether value is an array + + This function returns true iff the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return m_type == value_t::array; + } + + /*! + @brief return whether value is a string + + This function returns true iff the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return m_type == value_t::string; + } + + /*! + @brief return whether value is discarded + + This function returns true iff the JSON value was discarded during parsing + with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get an object (explicit) + template ::value and + std::is_convertible::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_object()) + { + assert(m_value.object != nullptr); + return T(m_value.object->begin(), m_value.object->end()); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } + } + + /// get an object (explicit) + object_t get_impl(object_t*) const + { + if (is_object()) + { + assert(m_value.object != nullptr); + return *(m_value.object); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not std::is_same::value and + not std::is_arithmetic::value and + not std::is_convertible::value and + not has_mapped_type::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_array()) + { + T to_vector; + assert(m_value.array != nullptr); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) + { + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not std::is_same::value + , int>::type = 0> + std::vector get_impl(std::vector*) const + { + if (is_array()) + { + std::vector to_vector; + assert(m_value.array != nullptr); + to_vector.reserve(m_value.array->size()); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) + { + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + template ::value and + not has_mapped_type::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_array()) + { + assert(m_value.array != nullptr); + return T(m_value.array->begin(), m_value.array->end()); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get an array (explicit) + array_t get_impl(array_t*) const + { + if (is_array()) + { + assert(m_value.array != nullptr); + return *(m_value.array); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } + } + + /// get a string (explicit) + template ::value + , int>::type = 0> + T get_impl(T*) const + { + if (is_string()) + { + assert(m_value.string != nullptr); + return *m_value.string; + } + else + { + throw std::domain_error("type must be string, but is " + type_name()); + } + } + + /// get a number (explicit) + template::value + , int>::type = 0> + T get_impl(T*) const + { + switch (m_type) + { + case value_t::number_integer: + { + return static_cast(m_value.number_integer); + } + + case value_t::number_unsigned: + { + return static_cast(m_value.number_unsigned); + } + + case value_t::number_float: + { + return static_cast(m_value.number_float); + } + + default: + { + throw std::domain_error("type must be number, but is " + type_name()); + } + } + } + + /// get a boolean (explicit) + constexpr boolean_t get_impl(boolean_t*) const + { + return is_boolean() + ? m_value.boolean + : throw std::domain_error("type must be boolean, but is " + type_name()); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t*) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t*) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t*) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t*) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t*) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t*) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t*) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t*) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t*) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This funcion helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw std::domain_error if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + using PointerType = typename std::add_pointer::type; + auto ptr = obj.template get_ptr(); + + if (ptr != nullptr) + { + return *ptr; + } + else + { + throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name()); + } + } + + public: + + /// @name value access + /// @{ + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays + + @return copy of the JSON value, converted to type @a ValueType + + @throw std::domain_error in case passed type @a ValueType is incompatible + to JSON; example: `"type must be object, but is null"` + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @internal + The idea of using a casted null pointer to choose the correct + implementation is from . + @endinternal + + @sa @ref operator ValueType() const for implicit conversion + @sa @ref get() for pointer-member access + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + ValueType get() const + { + return get_impl(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value + , int>::type = 0> + constexpr const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value + , int>::type = 0> + PointerType get_ptr() noexcept + { + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template::value + and std::is_const::type>::value + , int>::type = 0> + constexpr const PointerType get_ptr() const noexcept + { + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implict reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + std::domain_error otherwise + + @throw std::domain_error in case passed type @a ReferenceType is + incompatible with the stored JSON value + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value + , int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template::value + and std::is_const::type>::value + , int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw std::domain_error in case passed type @a ValueType is incompatible + to JSON, thrown by @ref get() const + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename + std::enable_if < + not std::is_pointer::value + and not std::is_same::value +#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 + and not std::is_same>::value +#endif + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` + @throw std::out_of_range if the index @a idx is out of range of the array; + that is, `idx >= size()`; example: `"array index 7 is out of range"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read and + written using `at()`.,at__size_type} + + @since version 1.0.0 + */ + reference at(size_type idx) + { + // at only works for arrays + if (is_array()) + { + try + { + assert(m_value.array != nullptr); + return m_value.array->at(idx); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw std::domain_error if the JSON value is not an array; example: + `"cannot use at() with string"` + @throw std::out_of_range if the index @a idx is out of range of the array; + that is, `idx >= size()`; example: `"array index 7 is out of range"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + `at()`.,at__size_type_const} + + @since version 1.0.0 + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (is_array()) + { + try + { + assert(m_value.array != nullptr); + return m_value.array->at(idx); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` + @throw std::out_of_range if the key @a key is is not stored in the object; + that is, `find(key) == end()`; example: `"key "the fast" not found"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using `at()`.,at__object_t_key_type} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (is_object()) + { + try + { + assert(m_value.object != nullptr); + return m_value.object->at(key); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if the JSON value is not an object; example: + `"cannot use at() with boolean"` + @throw std::out_of_range if the key @a key is is not stored in the object; + that is, `find(key) == end()`; example: `"key "the fast" not found"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + `at()`.,at__object_t_key_type_const} + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (is_object()) + { + try + { + assert(m_value.object != nullptr); + return m_value.object->at(key); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw std::domain_error if JSON is not an array or null; example: + `"cannot use operator[] with string"` + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + } + + // operator[] only works for arrays + if (is_array()) + { + // fill up array with null values until given idx is reached + assert(m_value.array != nullptr); + for (size_t i = m_value.array->size(); i <= idx; ++i) + { + m_value.array->push_back(basic_json()); + } + + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw std::domain_error if JSON is not an array; example: `"cannot use + operator[] with null"` + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (is_array()) + { + assert(m_value.array != nullptr); + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with string"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + } + + // operator[] only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with string"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + template + reference operator[](T * (&key)[n]) + { + return operator[](static_cast(key)); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @note This function is required for compatibility reasons with Clang. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + */ + template + const_reference operator[](T * (&key)[n]) const + { + return operator[](static_cast(key)); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with string"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + } + + // at only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object; example: `"cannot use + operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + const_reference operator[](T* key) const + { + // at only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key or + a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(std::out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw std::domain_error if JSON is not an object; example: `"cannot use + value() with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + template ::value + , int>::type = 0> + ValueType value(const typename object_t::key_type& key, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + else + { + return default_value; + } + } + else + { + throw std::domain_error("cannot use value() with " + type_name()); + } + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value() + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In cast of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, guarded by assertions). + @post The JSON value remains unchanged. + + @throw std::out_of_range when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In cast of number, string, or boolean values, a + reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, guarded by assertions). + @post The JSON value remains unchanged. + + @throw std::out_of_range when called on `null` value. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam InteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw std::domain_error if called on a `null` value; example: `"cannot + use erase() with null"` + @throw std::domain_error if called on an iterator which does not belong to + the current JSON value; example: `"iterator does not fit current value"` + @throw std::out_of_range if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between pos and the end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + InteratorType erase(InteratorType pos) + { + // make sure iterator fits the current value + if (this != pos.m_object) + { + throw std::domain_error("iterator does not fit current value"); + } + + InteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not pos.m_it.primitive_iterator.is_begin()) + { + throw std::out_of_range("iterator out of range"); + } + + if (is_string()) + { + delete m_value.string; + m_value.string = nullptr; + } + + m_type = value_t::null; + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + default: + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam InteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw std::domain_error if called on a `null` value; example: `"cannot + use erase() with null"` + @throw std::domain_error if called on iterators which does not belong to + the current JSON value; example: `"iterators do not fit current value"` + @throw std::out_of_range if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template ::value or + std::is_same::value + , int>::type + = 0> + InteratorType erase(InteratorType first, InteratorType last) + { + // make sure iterator fits the current value + if (this != first.m_object or this != last.m_object) + { + throw std::domain_error("iterators do not fit current value"); + } + + InteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + throw std::out_of_range("iterators out of range"); + } + + if (is_string()) + { + delete m_value.string; + m_value.string = nullptr; + } + + m_type = value_t::null; + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + default: + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw std::domain_error when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->erase(key); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw std::domain_error when called on a type other than JSON array; + example: `"cannot use erase() with null"` + @throw std::out_of_range when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa @ref erase(InteratorType) -- removes the element at a given position + @sa @ref erase(InteratorType, InteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (is_array()) + { + if (idx >= size()) + { + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + + assert(m_value.array != nullptr); + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } + } + + /// @} + + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @param[in] key key value of the element to search for + + @return Iterator to an element with key equivalent to @a key. If no such + element is found, past-the-end (see end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + iterator find(typename object_t::key_type key) + { + auto result = end(); + + if (is_object()) + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(typename object_t::key_type) + */ + const_iterator find(typename object_t::key_type key) const + { + auto result = cend(); + + if (is_object()) + { + assert(m_value.object != nullptr); + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + size_type count(typename object_t::key_type key) const + { + // return 0 for all nonobject types + assert(not is_object() or m_value.object != nullptr); + return is_object() ? m_value.object->count(key) : 0; + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + private: + // forward declaration + template class iteration_proxy; + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + @note The name of this function is not yet final and may change in the + future. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty + + Checks if a JSON value has no elements. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->empty(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->empty(); + } + + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->size(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->size(); + } + + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + assert(m_value.array != nullptr); + return m_value.array->max_size(); + } + + case value_t::object: + { + assert(m_value.object != nullptr); + return m_value.object->max_size(); + } + + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @note Floating-point numbers are set to `0.0` which will be serialized to + `0`. The vale type remains @ref number_float_t. + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + assert(m_value.string != nullptr); + m_value.string->clear(); + break; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + m_value.array->clear(); + break; + } + + case value_t::object: + { + assert(m_value.object != nullptr); + m_value.object->clear(); + break; + } + + default: + { + break; + } + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw std::domain_error when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + } + + // add element to array (move semantics) + assert(m_value.array != nullptr); + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + } + + // add element to array + assert(m_value.array != nullptr); + m_value.array->push_back(val); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw std::domain_error when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (not(is_null() or is_object())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + } + + // add element to array + assert(m_value.object != nullptr); + m_value.object->insert(val); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(std::initializer_list init) + { + if (is_object() and init.size() == 2 and init.begin()->is_string()) + { + const string_t key = *init.begin(); + push_back(typename object_t::value_type(key, *(init.begin() + 1))); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(std::initializer_list) + */ + reference operator+=(std::initializer_list init) + { + push_back(init); + return *this; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between pos and end of the + container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + else + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (is_array()) + { + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + else + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + @throw std::domain_error if @a first and @a last do not belong to the same + JSON value; example: `"iterators do not fit"` + @throw std::domain_error if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (not is_array()) + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // check if range iterators belong to the same JSON object + if (first.m_object != last.m_object) + { + throw std::domain_error("iterators do not fit"); + } + + if (first.m_object == this or last.m_object == this) + { + throw std::domain_error("passed iterators may not belong to container"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw std::domain_error if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw std::domain_error if @a pos is not an iterator of *this; example: + `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, std::initializer_list ilist) + { + // insert only works for arrays + if (not is_array()) + { + throw std::domain_error("cannot use insert() with " + type_name()); + } + + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } + + // insert to array and return iterator + iterator result(this); + assert(m_value.array != nullptr); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); + return result; + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw std::domain_error when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) + { + // swap only works for arrays + if (is_array()) + { + assert(m_value.array != nullptr); + std::swap(*(m_value.array), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw std::domain_error when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) + { + // swap only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + std::swap(*(m_value.object), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw std::domain_error when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) + { + // swap only works for strings + if (is_string()) + { + assert(m_value.string != nullptr); + std::swap(*(m_value.string), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } + } + + /// @} + + + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + private: + /*! + @brief comparison operator for JSON types + + Returns an ordering that is similar to Python: + - order: null < boolean < number < object < array < string + - furthermore, each type is not smaller than itself + + @since version 1.0.0 + */ + friend bool operator<(const value_t lhs, const value_t rhs) noexcept + { + static constexpr std::array order = {{ + 0, // null + 3, // object + 4, // array + 5, // string + 1, // boolean + 2, // integer + 2, // unsigned + 2, // float + } + }; + + // discarded values are not comparable + if (lhs == value_t::discarded or rhs == value_t::discarded) + { + return false; + } + + return order[static_cast(lhs)] < order[static_cast(rhs)]; + } + + public: + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same. + - Integer and floating-point numbers are automatically converted before + comparison. Floating-point numbers are compared indirectly: two + floating-point numbers `f1` and `f2` are considered equal if neither + `f1 > f2` nor `f2 > f1` holds. + - Two JSON null values are equal. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); + return *lhs.m_value.array == *rhs.m_value.array; + } + case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); + return *lhs.m_value.object == *rhs.m_value.object; + } + case value_t::null: + { + return true; + } + case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); + return *lhs.m_value.string == *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean == rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer == rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float == rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + + return false; + } + + /*! + @brief comparison: equal + + The functions compares the given JSON value against a null pointer. As the + null pointer can be used to initialize a JSON value to null, a comparison + of JSON value @a v with a null pointer should be equivalent to call + `v.is_null()`. + + @param[in] v JSON value to consider + @return whether @a v is null + + @complexity Constant. + + @liveexample{The example compares several JSON types to the null pointer. + ,operator__equal__nullptr_t} + + @since version 1.0.0 + */ + friend bool operator==(const_reference v, std::nullptr_t) noexcept + { + return v.is_null(); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, std::nullptr_t) + */ + friend bool operator==(std::nullptr_t, const_reference v) noexcept + { + return v.is_null(); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } + + /*! + @brief comparison: not equal + + The functions compares the given JSON value against a null pointer. As the + null pointer can be used to initialize a JSON value to null, a comparison + of JSON value @a v with a null pointer should be equivalent to call + `not v.is_null()`. + + @param[in] v JSON value to consider + @return whether @a v is not null + + @complexity Constant. + + @liveexample{The example compares several JSON types to the null pointer. + ,operator__notequal__nullptr_t} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference v, std::nullptr_t) noexcept + { + return not v.is_null(); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, std::nullptr_t) + */ + friend bool operator!=(std::nullptr_t, const_reference v) noexcept + { + return not v.is_null(); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + assert(lhs.m_value.array != nullptr); + assert(rhs.m_value.array != nullptr); + return *lhs.m_value.array < *rhs.m_value.array; + } + case value_t::object: + { + assert(lhs.m_value.object != nullptr); + assert(rhs.m_value.object != nullptr); + return *lhs.m_value.object < *rhs.m_value.object; + } + case value_t::null: + { + return false; + } + case value_t::string: + { + assert(lhs.m_value.string != nullptr); + assert(rhs.m_value.string != nullptr); + return *lhs.m_value.string < *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean < rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer < rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float < rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } + + /// @} + + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. The + indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + // fix locale problems + auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); + + // do the actual serialization + j.dump(o, pretty_print, static_cast(indentation)); + + // reset locale + o.imbue(old_locale); + return o; + } + + /*! + @brief serialize to stream + @copydoc operator<<(std::ostream&, const basic_json&) + */ + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } + + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from string + + @param[in] s string to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @sa @ref parse(std::istream&, parser_callback_t) for a version that reads + from an input stream + + @since version 1.0.0 + */ + static basic_json parse(const string_t& s, parser_callback_t cb = nullptr) + { + return parser(s, cb).parse(); + } + + /*! + @brief deserialize from stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @sa @ref parse(const string_t&, parser_callback_t) for a version that + reads from a string + + @since version 1.0.0 + */ + static basic_json parse(std::istream& i, parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } + + /*! + @copydoc parse(std::istream&, parser_callback_t) + */ + static basic_json parse(std::istream&& i, parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw std::invalid_argument in case of parse errors + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, parser_callback_t) for a variant with a parser + callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + j = parser(i).parse(); + return i; + } + + /*! + @brief deserialize from stream + @copydoc operator<<(basic_json&, std::istream&) + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + j = parser(i).parse(); + return i; + } + + /// @} + + + private: + /////////////////////////// + // convenience functions // + /////////////////////////// + + /// return the type as string + string_t type_name() const noexcept + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + + /*! + @brief calculates the extra space to escape a JSON string + + @param[in] s the string to escape + @return the number of characters required to escape string @a s + + @complexity Linear in the length of string @a s. + */ + static std::size_t extra_space(const string_t& s) noexcept + { + std::size_t result = 0; + + for (const auto& c : s) + { + switch (c) + { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + result += 1; + break; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // from c (1 byte) to \uxxxx (6 bytes) + result += 5; + } + break; + } + } + } + + return result; + } + + /*! + @brief escape a string + + Escape a string by replacing certain special characters by a sequence of + an escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. + + @param[in] s the string to escape + @return the escaped string + + @complexity Linear in the length of string @a s. + */ + static string_t escape_string(const string_t& s) + { + const auto space = extra_space(s); + if (space == 0) + { + return s; + } + + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (const auto& c : s) + { + switch (c) + { + // quotation mark (0x22) + case '"': + { + result[pos + 1] = '"'; + pos += 2; + break; + } + + // reverse solidus (0x5c) + case '\\': + { + // nothing to change + pos += 2; + break; + } + + // backspace (0x08) + case '\b': + { + result[pos + 1] = 'b'; + pos += 2; + break; + } + + // formfeed (0x0c) + case '\f': + { + result[pos + 1] = 'f'; + pos += 2; + break; + } + + // newline (0x0a) + case '\n': + { + result[pos + 1] = 'n'; + pos += 2; + break; + } + + // carriage return (0x0d) + case '\r': + { + result[pos + 1] = 'r'; + pos += 2; + break; + } + + // horizontal tab (0x09) + case '\t': + { + result[pos + 1] = 't'; + pos += 2; + break; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // convert a number 0..15 to its hex representation + // (0..f) + const auto hexify = [](const int v) -> char + { + return (v < 10) + ? ('0' + static_cast(v)) + : ('a' + static_cast((v - 10) & 0x1f)); + }; + + // print character c as \uxxxx + for (const char m : + { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f) + }) + { + result[++pos] = m; + } + + ++pos; + } + else + { + // all other characters are added as-is + result[pos++] = c; + } + break; + } + } + } + + return result; + } + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. Note that + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + + @param[out] o stream to write to + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(std::ostream& o, + const bool pretty_print, + const unsigned int indent_step, + const unsigned int current_indent = 0) const + { + // variable to hold indentation for recursive calls + unsigned int new_indent = current_indent; + + switch (m_type) + { + case value_t::object: + { + assert(m_value.object != nullptr); + + if (m_value.object->empty()) + { + o << "{}"; + return; + } + + o << "{"; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) + { + if (i != m_value.object->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' ') << "\"" + << escape_string(i->first) << "\":" + << (pretty_print ? " " : ""); + i->second.dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') + "}"; + return; + } + + case value_t::array: + { + assert(m_value.array != nullptr); + + if (m_value.array->empty()) + { + o << "[]"; + return; + } + + o << "["; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) + { + if (i != m_value.array->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' '); + i->dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') << "]"; + return; + } + + case value_t::string: + { + assert(m_value.string != nullptr); + o << string_t("\"") << escape_string(*m_value.string) << "\""; + return; + } + + case value_t::boolean: + { + o << (m_value.boolean ? "true" : "false"); + return; + } + + case value_t::number_integer: + { + o << m_value.number_integer; + return; + } + + case value_t::number_unsigned: + { + o << m_value.number_unsigned; + return; + } + + case value_t::number_float: + { + if (m_value.number_float == 0) + { + // special case for zero to get "0.0"/"-0.0" + o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0"); + } + else + { + // Otherwise 6, 15 or 16 digits of precision allows + // round-trip IEEE 754 string->float->string, + // string->double->string or string->long + // double->string; to be safe, we read this value from + // std::numeric_limits::digits10 + o << std::setprecision(std::numeric_limits::digits10) + << m_value.number_float; + } + return; + } + + case value_t::discarded: + { + o << ""; + return; + } + + case value_t::null: + { + o << "null"; + return; + } + } + } + + private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + + + private: + /////////////// + // iterators // + /////////////// + + /*! + @brief an iterator for primitive JSON types + + This class models an iterator for primitive JSON types (boolean, number, + string). It's only purpose is to allow the iterator/const_iterator classes + to "iterate" over primitive values. Internally, the iterator is modeled by + a `difference_type` variable. Value begin_value (`0`) models the begin, + end_value (`1`) models past the end. + */ + class primitive_iterator_t + { + public: + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return (m_it == begin_value); + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return (m_it == end_value); + } + + /// return reference to the value to change and compare + operator difference_type& () noexcept + { + return m_it; + } + + /// return value to compare + constexpr operator difference_type () const noexcept + { + return m_it; + } + + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = std::numeric_limits::denorm_min(); + }; + + /*! + @brief an iterator value + + @note This structure could easily be a union, but MSVC currently does not + allow unions members with complex constructors, see + https://github.com/nlohmann/json/pull/105. + */ + struct internal_iterator + { + /// iterator for JSON objects + typename object_t::iterator object_iterator; + /// iterator for JSON arrays + typename array_t::iterator array_iterator; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator; + + /// create an uninitialized internal_iterator + internal_iterator() noexcept + : object_iterator(), array_iterator(), primitive_iterator() + {} + }; + + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy + { + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + size_t array_index = 0; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept + : anchor(it) + {} + + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// inequality operator (needed for range-based for) + bool operator!= (const iteration_proxy_internal& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + typename basic_json::string_t key() const + { + assert(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + return std::to_string(array_index); + } + + // use key from the object + case value_t::object: + { + return anchor.key(); + } + + // use an empty key for all primitive types + default: + { + return ""; + } + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; + + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) + : container(cont) + {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } + }; + + public: + /*! + @brief a const random access iterator for the @ref basic_json class + + This class implements a const iterator for the @ref basic_json class. From + this class, the @ref iterator class is derived. + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + + @since version 1.0.0 + */ + class const_iterator : public std::iterator + { + /// allow basic_json to access private members + friend class basic_json; + + public: + /// the type of the values when the iterator is dereferenced + using value_type = typename basic_json::value_type; + /// a type to represent differences between iterators + using difference_type = typename basic_json::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename basic_json::const_pointer; + /// defines a reference to the type iterated over (value_type) + using reference = typename basic_json::const_reference; + /// the category of the iterator + using iterator_category = std::bidirectional_iterator_tag; + + /// default constructor + const_iterator() = default; + + /// constructor for a given JSON instance + explicit const_iterator(pointer object) noexcept + : m_object(object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /// copy constructor given a nonconst iterator + explicit const_iterator(const iterator& other) noexcept + : m_object(other.m_object) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = other.m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = other.m_it.array_iterator; + break; + } + + default: + { + m_it.primitive_iterator = other.m_it.primitive_iterator; + break; + } + } + } + + /// copy constructor + const_iterator(const const_iterator& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /// copy assignment + const_iterator& operator=(const_iterator other) noexcept( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_object, other.m_object); + std::swap(m_it, other.m_it); + return *this; + } + + private: + /// set the iterator to the first value + void set_begin() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object != nullptr); + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array != nullptr); + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case basic_json::value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /// set the iterator past the last value + void set_end() noexcept + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object != nullptr); + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array != nullptr); + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /// return a reference to the value pointed to by the iterator + reference operator*() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case basic_json::value_t::null: + { + throw std::out_of_range("cannot get value"); + } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// dereference the iterator + pointer operator->() const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_object->m_value.object); + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case basic_json::value_t::array: + { + assert(m_object->m_value.array); + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// post-increment (it++) + const_iterator operator++(int) + { + auto result = *this; + ++(*this); + return result; + } + + /// pre-increment (++it) + const_iterator& operator++() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + ++m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + ++m_it.array_iterator; + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /// post-decrement (it--) + const_iterator operator--(int) + { + auto result = *this; + --(*this); + return result; + } + + /// pre-decrement (--it) + const_iterator& operator--() + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + --m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + --m_it.array_iterator; + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /// comparison: equal + bool operator==(const const_iterator& other) const + { + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + throw std::domain_error("cannot compare iterators of different containers"); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + return (m_it.object_iterator == other.m_it.object_iterator); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator == other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + } + + /// comparison: not equal + bool operator!=(const const_iterator& other) const + { + return not operator==(other); + } + + /// comparison: smaller + bool operator<(const const_iterator& other) const + { + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + throw std::domain_error("cannot compare iterators of different containers"); + } + + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot compare order of object iterators"); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator < other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + } + + /// comparison: less than or equal + bool operator<=(const const_iterator& other) const + { + return not other.operator < (*this); + } + + /// comparison: greater than + bool operator>(const const_iterator& other) const + { + return not operator<=(other); + } + + /// comparison: greater than or equal + bool operator>=(const const_iterator& other) const + { + return not operator<(other); + } + + /// add to iterator + const_iterator& operator+=(difference_type i) + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use offsets with object iterators"); + } + + case basic_json::value_t::array: + { + m_it.array_iterator += i; + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /// subtract from iterator + const_iterator& operator-=(difference_type i) + { + return operator+=(-i); + } + + /// add to iterator + const_iterator operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + const_iterator operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const const_iterator& other) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use offsets with object iterators"); + } + + case basic_json::value_t::array: + { + return m_it.array_iterator - other.m_it.array_iterator; + } + + default: + { + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + } + + /// access to successor + reference operator[](difference_type n) const + { + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + throw std::domain_error("cannot use operator[] for object iterators"); + } + + case basic_json::value_t::array: + { + return *(m_it.array_iterator + n); + } + + case basic_json::value_t::null: + { + throw std::out_of_range("cannot get value"); + } + + default: + { + if (m_it.primitive_iterator == -n) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } + } + } + + /// return the key of an object iterator + typename object_t::key_type key() const + { + assert(m_object != nullptr); + + if (m_object->is_object()) + { + return m_it.object_iterator->first; + } + else + { + throw std::domain_error("cannot use key() for non-object iterators"); + } + } + + /// return the value of an iterator + reference value() const + { + return operator*(); + } + + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator m_it = internal_iterator(); + }; + + /*! + @brief a mutable random access iterator for the @ref basic_json class + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element. + + @since version 1.0.0 + */ + class iterator : public const_iterator + { + public: + using base_iterator = const_iterator; + using pointer = typename basic_json::pointer; + using reference = typename basic_json::reference; + + /// default constructor + iterator() = default; + + /// constructor for a given JSON instance + explicit iterator(pointer object) noexcept + : base_iterator(object) + {} + + /// copy constructor + iterator(const iterator& other) noexcept + : base_iterator(other) + {} + + /// copy assignment + iterator& operator=(iterator other) noexcept( + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value + ) + { + base_iterator::operator=(other); + return *this; + } + + /// return a reference to the value pointed to by the iterator + reference operator*() const + { + return const_cast(base_iterator::operator*()); + } + + /// dereference the iterator + pointer operator->() const + { + return const_cast(base_iterator::operator->()); + } + + /// post-increment (it++) + iterator operator++(int) + { + iterator result = *this; + base_iterator::operator++(); + return result; + } + + /// pre-increment (++it) + iterator& operator++() + { + base_iterator::operator++(); + return *this; + } + + /// post-decrement (it--) + iterator operator--(int) + { + iterator result = *this; + base_iterator::operator--(); + return result; + } + + /// pre-decrement (--it) + iterator& operator--() + { + base_iterator::operator--(); + return *this; + } + + /// add to iterator + iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } + + /// subtract from iterator + iterator& operator-=(difference_type i) + { + base_iterator::operator-=(i); + return *this; + } + + /// add to iterator + iterator operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + iterator operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const iterator& other) const + { + return base_iterator::operator-(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return const_cast(base_iterator::operator[](n)); + } + + /// return the value of an iterator + reference value() const + { + return const_cast(base_iterator::value()); + } + }; + + /*! + @brief a template for a reverse iterator class + + @tparam Base the base iterator type to reverse. Valid types are @ref + iterator (to create @ref reverse_iterator) and @ref const_iterator (to + create @ref const_reverse_iterator). + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + + @since version 1.0.0 + */ + template + class json_reverse_iterator : public std::reverse_iterator + { + public: + /// shortcut to the reverse iterator adaptor + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) + {} + + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) noexcept + : base_iterator(it) + {} + + /// post-increment (it++) + json_reverse_iterator operator++(int) + { + return base_iterator::operator++(1); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + base_iterator::operator++(); + return *this; + } + + /// post-decrement (it--) + json_reverse_iterator operator--(int) + { + return base_iterator::operator--(1); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + base_iterator::operator--(); + return *this; + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return this->base() - other.base(); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + typename object_t::key_type key() const + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } + }; + + + private: + ////////////////////// + // lexer and parser // + ////////////////////// + + /*! + @brief lexical analysis + + This class organizes the lexical analysis during JSON deserialization. The + core of it is a scanner generated by [re2c](http://re2c.org) that + processes a buffer and recognizes tokens according to RFC 7159. + */ + class lexer + { + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_number, ///< a number -- use get_number() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input ///< indicating the end of the input buffer + }; + + /// the char type to use in the lexer + using lexer_char_t = unsigned char; + + /// constructor with a given buffer + explicit lexer(const string_t& s) noexcept + : m_stream(nullptr), m_buffer(s) + { + m_content = reinterpret_cast(s.c_str()); + assert(m_content != nullptr); + m_start = m_cursor = m_content; + m_limit = m_content + s.size(); + } + + /// constructor with a given stream + explicit lexer(std::istream* s) noexcept + : m_stream(s), m_buffer() + { + assert(m_stream != nullptr); + getline(*m_stream, m_buffer); + m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); + m_start = m_cursor = m_content; + m_limit = m_content + m_buffer.size(); + } + + /// default constructor + lexer() = default; + + // switch off unwanted functions + lexer(const lexer&) = delete; + lexer operator=(const lexer&) = delete; + + /*! + @brief create a string from a Unicode code point + + @param[in] codepoint1 the code point (can be high surrogate) + @param[in] codepoint2 the code point (can be low surrogate or 0) + + @return string representation of the code point + + @throw std::out_of_range if code point is > 0x10ffff; example: `"code + points above 0x10FFFF are invalid"` + @throw std::invalid_argument if the low surrogate is invalid; example: + `""missing or wrong low surrogate""` + + @see + */ + static string_t to_unicode(const std::size_t codepoint1, + const std::size_t codepoint2 = 0) + { + // calculate the codepoint from the given code points + std::size_t codepoint = codepoint1; + + // check if codepoint1 is a high surrogate + if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) + { + // check if codepoint2 is a low surrogate + if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) + { + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + throw std::invalid_argument("missing or wrong low surrogate"); + } + } + + string_t result; + + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + result.append(1, static_cast(codepoint)); + } + else if (codepoint <= 0x7ff) + { + // 2-byte characters: 110xxxxx 10xxxxxx + result.append(1, static_cast(0xC0 | ((codepoint >> 6) & 0x1F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0xffff) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xE0 | ((codepoint >> 12) & 0x0F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0x10ffff) + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xF0 | ((codepoint >> 18) & 0x07))); + result.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else + { + throw std::out_of_range("code points above 0x10FFFF are invalid"); + } + + return result; + } + + /// return name of values of type token_type (only used for errors) + static std::string token_type_name(token_type t) + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_number: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + default: + { + // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + } + + /*! + This function implements a scanner for JSON. It is specified using + regular expressions that try to follow RFC 7159 as close as possible. + These regular expressions are then translated into a minimized + deterministic finite automaton (DFA) by the tool + [re2c](http://re2c.org). As a result, the translated code for this + function consists of a large block of code with `goto` jumps. + + @return the class of the next token read from the buffer + */ + token_type scan() noexcept + { + // pointer for backtracking information + m_marker = nullptr; + + // remember the begin of the token + m_start = m_cursor; + assert(m_start != nullptr); + + + { + lexer_char_t yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 32, 0, 0, 32, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 160, 128, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 0, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + }; + if ((m_limit - m_cursor) < 5) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + if (yych <= '\\') + { + if (yych <= '-') + { + if (yych <= '"') + { + if (yych <= 0x00) + { + goto basic_json_parser_2; + } + if (yych <= '!') + { + goto basic_json_parser_4; + } + goto basic_json_parser_9; + } + else + { + if (yych <= '+') + { + goto basic_json_parser_4; + } + if (yych <= ',') + { + goto basic_json_parser_10; + } + goto basic_json_parser_12; + } + } + else + { + if (yych <= '9') + { + if (yych <= '/') + { + goto basic_json_parser_4; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + goto basic_json_parser_15; + } + else + { + if (yych <= ':') + { + goto basic_json_parser_17; + } + if (yych == '[') + { + goto basic_json_parser_19; + } + goto basic_json_parser_4; + } + } + } + else + { + if (yych <= 't') + { + if (yych <= 'f') + { + if (yych <= ']') + { + goto basic_json_parser_21; + } + if (yych <= 'e') + { + goto basic_json_parser_4; + } + goto basic_json_parser_23; + } + else + { + if (yych == 'n') + { + goto basic_json_parser_24; + } + if (yych <= 's') + { + goto basic_json_parser_4; + } + goto basic_json_parser_25; + } + } + else + { + if (yych <= '|') + { + if (yych == '{') + { + goto basic_json_parser_26; + } + goto basic_json_parser_4; + } + else + { + if (yych <= '}') + { + goto basic_json_parser_28; + } + if (yych == 0xEF) + { + goto basic_json_parser_30; + } + goto basic_json_parser_4; + } + } + } +basic_json_parser_2: + ++m_cursor; + { + return token_type::end_of_input; + } +basic_json_parser_4: + ++m_cursor; +basic_json_parser_5: + { + return token_type::parse_error; + } +basic_json_parser_6: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + { + return scan(); + } +basic_json_parser_9: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych <= 0x0F) + { + goto basic_json_parser_5; + } + goto basic_json_parser_32; +basic_json_parser_10: + ++m_cursor; + { + return token_type::value_separator; + } +basic_json_parser_12: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_5; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + if (yych <= '9') + { + goto basic_json_parser_15; + } + goto basic_json_parser_5; +basic_json_parser_13: + yyaccept = 1; + yych = *(m_marker = ++m_cursor); + if (yych <= 'D') + { + if (yych == '.') + { + goto basic_json_parser_37; + } + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + } +basic_json_parser_14: + { + return token_type::value_number; + } +basic_json_parser_15: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yybm[0 + yych] & 64) + { + goto basic_json_parser_15; + } + if (yych <= 'D') + { + if (yych == '.') + { + goto basic_json_parser_37; + } + goto basic_json_parser_14; + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + goto basic_json_parser_14; + } +basic_json_parser_17: + ++m_cursor; + { + return token_type::name_separator; + } +basic_json_parser_19: + ++m_cursor; + { + return token_type::begin_array; + } +basic_json_parser_21: + ++m_cursor; + { + return token_type::end_array; + } +basic_json_parser_23: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'a') + { + goto basic_json_parser_39; + } + goto basic_json_parser_5; +basic_json_parser_24: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'u') + { + goto basic_json_parser_40; + } + goto basic_json_parser_5; +basic_json_parser_25: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'r') + { + goto basic_json_parser_41; + } + goto basic_json_parser_5; +basic_json_parser_26: + ++m_cursor; + { + return token_type::begin_object; + } +basic_json_parser_28: + ++m_cursor; + { + return token_type::end_object; + } +basic_json_parser_30: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 0xBB) + { + goto basic_json_parser_42; + } + goto basic_json_parser_5; +basic_json_parser_31: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; +basic_json_parser_32: + if (yybm[0 + yych] & 128) + { + goto basic_json_parser_31; + } + if (yych <= 0x0F) + { + goto basic_json_parser_33; + } + if (yych <= '"') + { + goto basic_json_parser_34; + } + goto basic_json_parser_36; +basic_json_parser_33: + m_cursor = m_marker; + if (yyaccept == 0) + { + goto basic_json_parser_5; + } + else + { + goto basic_json_parser_14; + } +basic_json_parser_34: + ++m_cursor; + { + return token_type::value_string; + } +basic_json_parser_36: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= 'e') + { + if (yych <= '/') + { + if (yych == '"') + { + goto basic_json_parser_31; + } + if (yych <= '.') + { + goto basic_json_parser_33; + } + goto basic_json_parser_31; + } + else + { + if (yych <= '\\') + { + if (yych <= '[') + { + goto basic_json_parser_33; + } + goto basic_json_parser_31; + } + else + { + if (yych == 'b') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + } + } + else + { + if (yych <= 'q') + { + if (yych <= 'f') + { + goto basic_json_parser_31; + } + if (yych == 'n') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 's') + { + if (yych <= 'r') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 't') + { + goto basic_json_parser_31; + } + if (yych <= 'u') + { + goto basic_json_parser_43; + } + goto basic_json_parser_33; + } + } + } +basic_json_parser_37: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_44; + } + goto basic_json_parser_33; +basic_json_parser_38: + yych = *++m_cursor; + if (yych <= ',') + { + if (yych == '+') + { + goto basic_json_parser_46; + } + goto basic_json_parser_33; + } + else + { + if (yych <= '-') + { + goto basic_json_parser_46; + } + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_47; + } + goto basic_json_parser_33; + } +basic_json_parser_39: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_49; + } + goto basic_json_parser_33; +basic_json_parser_40: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_50; + } + goto basic_json_parser_33; +basic_json_parser_41: + yych = *++m_cursor; + if (yych == 'u') + { + goto basic_json_parser_51; + } + goto basic_json_parser_33; +basic_json_parser_42: + yych = *++m_cursor; + if (yych == 0xBF) + { + goto basic_json_parser_52; + } + goto basic_json_parser_33; +basic_json_parser_43: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_54; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_54; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_54; + } + goto basic_json_parser_33; + } +basic_json_parser_44: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= 'D') + { + if (yych <= '/') + { + goto basic_json_parser_14; + } + if (yych <= '9') + { + goto basic_json_parser_44; + } + goto basic_json_parser_14; + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_38; + } + if (yych == 'e') + { + goto basic_json_parser_38; + } + goto basic_json_parser_14; + } +basic_json_parser_46: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych >= ':') + { + goto basic_json_parser_33; + } +basic_json_parser_47: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '/') + { + goto basic_json_parser_14; + } + if (yych <= '9') + { + goto basic_json_parser_47; + } + goto basic_json_parser_14; +basic_json_parser_49: + yych = *++m_cursor; + if (yych == 's') + { + goto basic_json_parser_55; + } + goto basic_json_parser_33; +basic_json_parser_50: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_56; + } + goto basic_json_parser_33; +basic_json_parser_51: + yych = *++m_cursor; + if (yych == 'e') + { + goto basic_json_parser_58; + } + goto basic_json_parser_33; +basic_json_parser_52: + ++m_cursor; + { + return scan(); + } +basic_json_parser_54: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_60; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_60; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_60; + } + goto basic_json_parser_33; + } +basic_json_parser_55: + yych = *++m_cursor; + if (yych == 'e') + { + goto basic_json_parser_61; + } + goto basic_json_parser_33; +basic_json_parser_56: + ++m_cursor; + { + return token_type::literal_null; + } +basic_json_parser_58: + ++m_cursor; + { + return token_type::literal_true; + } +basic_json_parser_60: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_63; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_63; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_63; + } + goto basic_json_parser_33; + } +basic_json_parser_61: + ++m_cursor; + { + return token_type::literal_false; + } +basic_json_parser_63: + ++m_cursor; + if (m_limit <= m_cursor) + { + yyfill(); // LCOV_EXCL_LINE; + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') + { + goto basic_json_parser_33; + } + if (yych <= '9') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + else + { + if (yych <= 'F') + { + goto basic_json_parser_31; + } + if (yych <= '`') + { + goto basic_json_parser_33; + } + if (yych <= 'f') + { + goto basic_json_parser_31; + } + goto basic_json_parser_33; + } + } + + } + + /// append data from the stream to the internal buffer + void yyfill() noexcept + { + if (m_stream == nullptr or not * m_stream) + { + return; + } + + const auto offset_start = m_start - m_content; + const auto offset_marker = m_marker - m_start; + const auto offset_cursor = m_cursor - m_start; + + m_buffer.erase(0, static_cast(offset_start)); + std::string line; + assert(m_stream != nullptr); + std::getline(*m_stream, line); + m_buffer += "\n" + line; // add line with newline symbol + + m_content = reinterpret_cast(m_buffer.c_str()); + assert(m_content != nullptr); + m_start = m_content; + m_marker = m_start + offset_marker; + m_cursor = m_start + offset_cursor; + m_limit = m_start + m_buffer.size() - 1; + } + + /// return string representation of last read token + string_t get_token() const + { + assert(m_start != nullptr); + return string_t(reinterpret_cast(m_start), + static_cast(m_cursor - m_start)); + } + + /*! + @brief return string value for string tokens + + The function iterates the characters between the opening and closing + quotes of the string value. The complete string is the range + [m_start,m_cursor). Consequently, we iterate from m_start+1 to + m_cursor-1. + + We differentiate two cases: + + 1. Escaped characters. In this case, a new character is constructed + according to the nature of the escape. Some escapes create new + characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied + as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape + `"\\uxxxx"` need special care. In this case, to_unicode takes care + of the construction of the values. + 2. Unescaped characters are copied as is. + + @return string value of current token without opening and closing + quotes + @throw std::out_of_range if to_unicode fails + */ + string_t get_string() const + { + string_t result; + result.reserve(static_cast(m_cursor - m_start - 2)); + + // iterate the result between the quotes + for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) + { + // process escaped characters + if (*i == '\\') + { + // read next character + ++i; + + switch (*i) + { + // the default escapes + case 't': + { + result += "\t"; + break; + } + case 'b': + { + result += "\b"; + break; + } + case 'f': + { + result += "\f"; + break; + } + case 'n': + { + result += "\n"; + break; + } + case 'r': + { + result += "\r"; + break; + } + case '\\': + { + result += "\\"; + break; + } + case '/': + { + result += "/"; + break; + } + case '"': + { + result += "\""; + break; + } + + // unicode + case 'u': + { + // get code xxxx from uxxxx + auto codepoint = std::strtoul(std::string(reinterpret_cast(i + 1), + 4).c_str(), nullptr, 16); + + // check if codepoint is a high surrogate + if (codepoint >= 0xD800 and codepoint <= 0xDBFF) + { + // make sure there is a subsequent unicode + if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') + { + throw std::invalid_argument("missing low surrogate"); + } + + // get code yyyy from uxxxx\uyyyy + auto codepoint2 = std::strtoul(std::string(reinterpret_cast + (i + 7), 4).c_str(), nullptr, 16); + result += to_unicode(codepoint, codepoint2); + // skip the next 10 characters (xxxx\uyyyy) + i += 10; + } + else + { + // add unicode character(s) + result += to_unicode(codepoint); + // skip the next four characters (xxxx) + i += 4; + } + break; + } + } + } + else + { + // all other characters are just copied to the end of the + // string + result.append(1, static_cast(*i)); + } + } + + return result; + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to @a + static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + + @bug This function uses `std::strtof`, `std::strtod`, or `std::strtold` + which use the current C locale to determine which character is used as + decimal point character. This may yield to parse errors if the locale + does not used `.`. + */ + long double str_to_float_t(long double* /* type */, char** endptr) const + { + return std::strtold(reinterpret_cast(m_start), endptr); + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to @a + static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + */ + double str_to_float_t(double* /* type */, char** endptr) const + { + return std::strtod(reinterpret_cast(m_start), endptr); + } + + /*! + @brief parse floating point number + + This function (and its overloads) serves to select the most approprate + standard floating point number parsing function based on the type + supplied via the first parameter. Set this to @a + static_cast(nullptr). + + @param[in] type the @ref number_float_t in use + + @param[in,out] endptr recieves a pointer to the first character after + the number + + @return the floating point number + */ + float str_to_float_t(float* /* type */, char** endptr) const + { + return std::strtof(reinterpret_cast(m_start), endptr); + } + + /*! + @brief return number value for number tokens + + This function translates the last token into the most appropriate + number type (either integer, unsigned integer or floating point), + which is passed back to the caller via the result parameter. + + This function parses the integer component up to the radix point or + exponent while collecting information about the 'floating point + representation', which it stores in the result parameter. If there is + no radix point or exponent, and the number can fit into a @ref + number_integer_t or @ref number_unsigned_t then it sets the result + parameter accordingly. + + If the number is a floating point number the number is then parsed + using @a std:strtod (or @a std:strtof or @a std::strtold). + + @param[out] result @ref basic_json object to receive the number, or + NAN if the conversion read past the current token. The latter case + needs to be treated by the caller function. + */ + void get_number(basic_json& result) const + { + assert(m_start != nullptr); + + const lexer::lexer_char_t* curptr = m_start; + + // accumulate the integer conversion result (unsigned for now) + number_unsigned_t value = 0; + + // maximum absolute value of the relevant integer type + number_unsigned_t max; + + // temporarily store the type to avoid unecessary bitfield access + value_t type; + + // look for sign + if (*curptr == '-') + { + type = value_t::number_integer; + max = static_cast((std::numeric_limits::max)()) + 1; + curptr++; + } + else + { + type = value_t::number_unsigned; + max = static_cast((std::numeric_limits::max)()); + } + + // count the significant figures + for (; curptr < m_cursor; curptr++) + { + // quickly skip tests if a digit + if (*curptr < '0' || *curptr > '9') + { + if (*curptr == '.') + { + // don't count '.' but change to float + type = value_t::number_float; + continue; + } + // assume exponent (if not then will fail parse): change to + // float, stop counting and record exponent details + type = value_t::number_float; + break; + } + + // skip if definitely not an integer + if (type != value_t::number_float) + { + // multiply last value by ten and add the new digit + auto temp = value * 10 + *curptr - 0x30; + + // test for overflow + if (temp < value || temp > max) + { + // overflow + type = value_t::number_float; + } + else + { + // no overflow - save it + value = temp; + } + } + } + + // save the value (if not a float) + if (type == value_t::number_unsigned) + { + result.m_value.number_unsigned = value; + } + else if (type == value_t::number_integer) + { + result.m_value.number_integer = -static_cast(value); + } + else + { + // parse with strtod + result.m_value.number_float = str_to_float_t(static_cast(nullptr), NULL); + } + + // save the type + result.m_type = type; + } + + private: + /// optional input stream + std::istream* m_stream = nullptr; + /// the buffer + string_t m_buffer; + /// the buffer pointer + const lexer_char_t* m_content = nullptr; + /// pointer to the beginning of the current symbol + const lexer_char_t* m_start = nullptr; + /// pointer for backtracking information + const lexer_char_t* m_marker = nullptr; + /// pointer to the current symbol + const lexer_char_t* m_cursor = nullptr; + /// pointer to the end of the buffer + const lexer_char_t* m_limit = nullptr; + }; + + /*! + @brief syntax analysis + + This class implements a recursive decent parser. + */ + class parser + { + public: + /// constructor for strings + parser(const string_t& s, parser_callback_t cb = nullptr) noexcept + : callback(cb), m_lexer(s) + { + // read first token + get_token(); + } + + /// a parser reading from an input stream + parser(std::istream& _is, parser_callback_t cb = nullptr) noexcept + : callback(cb), m_lexer(&_is) + { + // read first token + get_token(); + } + + /// public parser interface + basic_json parse() + { + basic_json result = parse_internal(true); + + expect(lexer::token_type::end_of_input); + + // return parser result and replace it with null in case the + // top-level value was discarded by the callback function + return result.is_discarded() ? basic_json() : result; + } + + private: + /// the actual parser + basic_json parse_internal(bool keep) + { + auto result = basic_json(value_t::discarded); + + switch (last_token) + { + case lexer::token_type::begin_object: + { + if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result)))) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = json_value(value_t::object); + } + + // read next token + get_token(); + + // closing } -> we are done + if (last_token == lexer::token_type::end_object) + { + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse key-value pairs + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // store key + expect(lexer::token_type::value_string); + const auto key = m_lexer.get_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + basic_json k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + expect(lexer::token_type::name_separator); + + // parse and add value + get_token(); + auto value = parse_internal(keep); + if (keep and keep_tag and not value.is_discarded()) + { + result[key] = std::move(value); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing } + expect(lexer::token_type::end_object); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + + return result; + } + + case lexer::token_type::begin_array: + { + if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result)))) + { + // explicitly set result to object to cope with [] + result.m_type = value_t::array; + result.m_value = json_value(value_t::array); + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == lexer::token_type::end_array) + { + get_token(); + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse values + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // parse value + auto value = parse_internal(keep); + if (keep and not value.is_discarded()) + { + result.push_back(std::move(value)); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing ] + expect(lexer::token_type::end_array); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + + return result; + } + + case lexer::token_type::literal_null: + { + get_token(); + result.m_type = value_t::null; + break; + } + + case lexer::token_type::value_string: + { + const auto s = m_lexer.get_string(); + get_token(); + result = basic_json(s); + break; + } + + case lexer::token_type::literal_true: + { + get_token(); + result.m_type = value_t::boolean; + result.m_value = true; + break; + } + + case lexer::token_type::literal_false: + { + get_token(); + result.m_type = value_t::boolean; + result.m_value = false; + break; + } + + case lexer::token_type::value_number: + { + m_lexer.get_number(result); + get_token(); + break; + } + + default: + { + // the last token was unexpected + unexpect(last_token); + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + /// get next token from lexer + typename lexer::token_type get_token() noexcept + { + last_token = m_lexer.scan(); + return last_token; + } + + void expect(typename lexer::token_type t) const + { + if (t != last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); + error_msg += "; expected " + lexer::token_type_name(t); + throw std::invalid_argument(error_msg); + } + } + + void unexpect(typename lexer::token_type t) const + { + if (t == last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") : + lexer::token_type_name(last_token)); + throw std::invalid_argument(error_msg); + } + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + parser_callback_t callback; + /// the type of the last read token + typename lexer::token_type last_token = lexer::token_type::uninitialized; + /// the lexer + lexer m_lexer; + }; + + public: + /*! + @brief JSON Pointer + + A JSON pointer defines a string syntax for identifying a specific value + within a JSON document. It can be used with functions `at` and + `operator[]`. Furthermore, JSON pointers are the base for JSON patches. + + @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + class json_pointer + { + /// allow basic_json to access private members + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the + empty string is assumed which references the whole JSON + value + + @throw std::domain_error if reference token is nonempty and does not + begin with a slash (`/`); example: `"JSON pointer must be empty or + begin with /"` + @throw std::domain_error if a tilde (`~`) is not followed by `0` + (representing `~`) or `1` (representing `/`); example: `"escape error: + ~ must be followed with 0 or 1"` + + @liveexample{The example shows the construction several valid JSON + pointers as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") + : reference_tokens(split(s)) + {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const noexcept + { + std::string result; + + for (const auto& reference_token : reference_tokens) + { + result += "/" + escape(reference_token); + } + + return result; + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + private: + /// remove and return last reference pointer + std::string pop_back() + { + if (is_root()) + { + throw std::domain_error("JSON pointer has no parent"); + } + + auto last = reference_tokens.back(); + reference_tokens.pop_back(); + return last; + } + + /// return whether pointer points to the root document + bool is_root() const + { + return reference_tokens.empty(); + } + + json_pointer top() const + { + if (is_root()) + { + throw std::domain_error("JSON pointer has no parent"); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! + @brief create and return a reference to the pointed to value + */ + reference get_and_create(reference j) const + { + pointer result = &j; + + // in case no reference tokens exist, return a reference to the + // JSON value j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->m_type) + { + case value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case value_t::array: + { + // create an entry in the array + result = &result->operator[](static_cast(std::stoi(reference_token))); + break; + } + + /* + The following code is only reached if there exists a + reference token _and_ the current value is primitive. In + this case, we have an error situation, because primitive + values may only occur as single value; that is, with an + empty list of reference tokens. + */ + default: + { + throw std::domain_error("invalid value to unflatten"); + } + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + */ + reference get_unchecked(pointer ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case value_t::array: + { + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + throw std::domain_error("array index must not begin with '0'"); + } + + if (reference_token == "-") + { + // explicityly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + } + break; + } + + default: + { + throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + } + } + } + + return *ptr; + } + + reference get_checked(pointer ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case value_t::array: + { + if (reference_token == "-") + { + // "-" always fails the range check + throw std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range"); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + throw std::domain_error("array index must not begin with '0'"); + } + + // note: at performs range check + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + break; + } + + default: + { + throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + } + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + */ + const_reference get_unchecked(const_pointer ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case value_t::array: + { + if (reference_token == "-") + { + // "-" cannot be used for const access + throw std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range"); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + throw std::domain_error("array index must not begin with '0'"); + } + + // use unchecked array access + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + break; + } + + default: + { + throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + } + } + } + + return *ptr; + } + + const_reference get_checked(const_pointer ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case value_t::array: + { + if (reference_token == "-") + { + // "-" always fails the range check + throw std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range"); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + throw std::domain_error("array index must not begin with '0'"); + } + + // note: at performs range check + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + break; + } + + default: + { + throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + } + } + } + + return *ptr; + } + + /// split the string input to reference tokens + static std::vector split(std::string reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (reference_string[0] != '/') + { + throw std::domain_error("JSON pointer must be empty or begin with '/'"); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + size_t slash = reference_string.find_first_of("/", 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == string::npos+1 = 0 + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = slash + 1, + // find next slash + slash = reference_string.find_first_of("/", start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (size_t pos = reference_token.find_first_of("~"); + pos != std::string::npos; + pos = reference_token.find_first_of("~", pos + 1)) + { + assert(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (pos == reference_token.size() - 1 or + (reference_token[pos + 1] != '0' and + reference_token[pos + 1] != '1')) + { + throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + private: + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate + @param[in] f the substring to replace with @a t + @param[out] t the string to replace @a f + + @return The string @a s where all occurrences of @a f are replaced + with @a t. + + @pre The search string @a f must not be empty. + + @since version 2.0.0 + */ + static void replace_substring(std::string& s, + const std::string& f, + const std::string& t) + { + assert(not f.empty()); + + for ( + size_t pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t + pos = s.find(f, pos + t.size()) // find next occurrence of f + ); + } + + /// escape tilde and slash + static std::string escape(std::string s) + { + // escape "~"" to "~0" and "/" to "~1" + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } + + /// unescape tilde and slash + static void unescape(std::string& s) + { + // first transform any occurrence of the sequence '~1' to '/' + replace_substring(s, "~1", "/"); + // then transform any occurrence of the sequence '~0' to '~' + replace_substring(s, "~0", "~"); + } + + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + static void flatten(const std::string& reference_string, + const basic_json& value, + basic_json& result) + { + switch (value.m_type) + { + case value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), + element.second, result); + } + } + break; + } + + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + */ + static basic_json unflatten(const basic_json& value) + { + if (not value.is_object()) + { + throw std::domain_error("only objects can be unflattened"); + } + + basic_json result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (not element.second.is_primitive()) + { + throw std::domain_error("values in object must be primitive"); + } + + // assign value to reference pointed to by JSON pointer; Note + // that if the JSON pointer is "" (i.e., points to the whole + // value), function get_and_create returns a reference to + // result itself. An assignment will then create a primitive + // value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + private: + /// the reference tokens + std::vector reference_tokens {}; + }; + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + + @liveexample{The behavior is shown in the example.,at_json_pointer} + + @since version 2.0.0 + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw std::out_of_range if the JSON pointer can not be resolved + @throw std::domain_error if an array index begins with '0' + @throw std::invalid_argument if an array index was not a number + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + + @since version 2.0.0 + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitve values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this funcion, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw std::out_of_range if a JSON pointer inside the patch could not + be resolved successfully in the current JSON value; example: `"key baz + not found"` + @throw invalid_argument if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.is_root()) + { + result = val; + } + else + { + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + basic_json& x = result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = std::stoi(last_path); + if (static_cast(idx) > parent.size()) + { + // avoid undefined behavior + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + else + { + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + } + break; + } + + default: + { + // if there exists a parent it cannot be primitive + assert(false); // LCOV_EXCL_LINE + } + } + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (it != parent.end()) + { + parent.erase(it); + } + else + { + throw std::out_of_range("key '" + last_path + "' not found"); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(static_cast(std::stoi(last_path))); + } + }; + + // type check + if (not json_patch.is_array()) + { + // a JSON patch must be an array of objects + throw std::invalid_argument("JSON patch must be an array of objects"); + } + + // iterate and apply th eoperations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json& + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (it == val.m_value.object->end()) + { + throw std::invalid_argument(error_msg + " must have member '" + member + "'"); + } + + // check if result is of type string + if (string_type and not it->second.is_string()) + { + throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); + } + + // no error: return value + return it->second; + }; + + // type check + if (not val.is_object()) + { + throw std::invalid_argument("JSON patch must be an array of objects"); + } + + // collect mandatory members + const std::string op = get_value("op", "op", true); + const std::string path = get_value(op, "path", true); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const std::string from_path = get_value("move", "from", true); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const std::string from_path = get_value("copy", "from", true);; + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + result[ptr] = result.at(from_ptr); + break; + } + + case patch_operations::test: + { + bool success = false; + try + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + catch (std::out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (not success) + { + throw std::domain_error("unsuccessful: " + val.dump()); + } + + break; + } + + case patch_operations::invalid: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + throw std::invalid_argument("operation value '" + op + "' is invalid"); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to copare from + @param[in] target JSON value to copare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa @ref patch -- apply a JSON patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + static basic_json diff(const basic_json& source, + const basic_json& target, + std::string path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, + {"path", path}, + {"value", target} + }); + } + else + { + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + size_t i = 0; + while (i < source.size() and i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + std::to_string(i)}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.begin(); it != source.end(); ++it) + { + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, + {"path", path + "/" + key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.begin(); it != target.end(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + key}, + {"value", it.value()} + }); + } + } + + break; + } + + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, + {"path", path}, + {"value", target} + }); + break; + } + } + } + + return result; + } + + /// @} +}; + + +///////////// +// presets // +///////////// + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} + + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template <> +inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +/// hash value for JSON objects +template <> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } +}; +} + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding \p "_json" to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@return a JSON object + +@since version 1.0.0 +*/ +inline nlohmann::json operator "" _json(const char* s, std::size_t) +{ + return nlohmann::json::parse(reinterpret_cast(s)); +} + +/*! +@brief user-defined string literal for JSON pointer + +@since version 2.0.0 +*/ +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t) +{ + return nlohmann::json::json_pointer(s); +} + +// restore GCC/clang diagnostic settings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic pop +#endif + +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.cpp new file mode 100644 index 0000000..67318cc --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.cpp @@ -0,0 +1,7557 @@ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#include "miniz.h" + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API's */ + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) + return MZ_ADLER32_INIT; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ +#if 0 + mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) + { + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) + return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) + { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; + } +#else +/* Faster, but larger CPU cache footprint. + */ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +{ + static const mz_uint32 s_crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, + 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, + 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, + 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, + 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, + 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, + 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, + 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, + 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, + 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, + 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, + 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, + 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, + 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, + 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, + 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, + 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, + 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, + 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, + 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, + 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, + 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, + 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; + const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; + + while (buf_len >= 4) + { + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; + pByte_buf += 4; + buf_len -= 4; + } + + while (buf_len) + { + crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; + ++pByte_buf; + --buf_len; + } + + return ~crc32; +} +#endif + +void mz_free(void *p) +{ + MZ_FREE(p); +} + +void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) +{ + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +void miniz_def_free_func(void *opaque, void *address) +{ + (void)opaque, (void)address; + MZ_FREE(address); +} +void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) +{ + (void)opaque, (void)address, (void)items, (void)size; + return MZ_REALLOC(address, items * size); +} + +const char *mz_version(void) +{ + return MZ_VERSION; +} + +#ifndef MINIZ_NO_ZLIB_APIS + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) + return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) + return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) + return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; /* Can't make forward progress without some input. + */ + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +{ + (void)pStream; + /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) + return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) +{ + return mz_deflateBound(NULL, source_len); +} + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) + return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) + pStream->zalloc = miniz_def_alloc_func; + if (!pStream->zfree) + pStream->zfree = miniz_def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) + return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) + decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) + return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + /* flush != MZ_FINISH then we must assume there's more input. */ + if (flush != MZ_FINISH) + decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for (;;) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ + else if (flush == MZ_FINISH) + { + /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + /* In case mz_ulong is 64-bits (argh I hate longs). */ + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) +{ + static struct + { + int m_err; + const char *m_pDesc; + } s_error_descs[] = + { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) + if (s_error_descs[i].m_err == err) + return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif /*MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Compression (independent from all decompression API's) */ + +/* Purposely making these tables static for faster init and thread safety. */ +static const mz_uint16 s_tdefl_len_sym[256] = + { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, + 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 + }; + +static const mz_uint8 s_tdefl_len_extra[256] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 + }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = + { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 + }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = + { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = + { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 + }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = + { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 + }; + +/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ +typedef struct +{ + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) + { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) + { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) + { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) + { + if (leaf >= n || A[root].m_key < A[leaf].m_key) + { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) + { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } + else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) + { + while (root >= 0 && (int)A[root].m_key == dpth) + { + used++; + root--; + } + while (avbl > used) + { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +/* Limits canonical Huffman code table's max code size. */ +enum +{ + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 +}; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) + return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) + { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) + { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) + continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do \ + { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) \ + { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) \ + { \ + if (rle_repeat_count < 3) \ + { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } \ + else \ + { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) \ + { \ + if (rle_z_count < 3) \ + { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) \ + packed_code_sizes[num_packed_code_sizes++] = 0; \ + } \ + else if (rle_z_count <= 10) \ + { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } \ + else \ + { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) + break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) + break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64 *)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ + if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) + { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) + { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) + { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } + else + { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) + { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) + { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#ifdef MINIZ_UNALIGNED_USE_MEMCPY +static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +static inline mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) +{ + mz_uint16 ret; + memcpy(&ret, p, sizeof(mz_uint16)); + return ret; +} +#else +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) +#endif +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) + continue; + p = s; + probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + if (!probe_len) + { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); + break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) + { + for (;;) + { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) + break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) + break; + if (probe_len > match_len) + { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) + return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) + break; + + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do + { + } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && + (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) + { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) + { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + /* Simple lazy/greedy parsing state machine. */ + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) + { + if (d->m_dict[cur_pos + cur_match_len] != c) + break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + /* Move the lookahead forward by len_to_move bytes. */ + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + /* Check if it's time to flush the current LZ codes to the internal output buffer. */ + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) + { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) + { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) + { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +{ + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +{ + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) + return MZ_FALSE; + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) + return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +{ + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) + return MZ_FALSE; + do + { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) + return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) + return MZ_FALSE; + else + *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) + return 0; + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return 0; + return out_buf.m_size; +} + +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) + comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ +#endif + +/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at + http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. + This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) +{ + /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ + static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) + return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) + { + MZ_FREE(pComp); + return NULL; + } + /* write dummy header */ + for (z = 41; z; --z) + tdefl_output_buffer_putter(&z, 1, &out_buf); + /* compress image data */ + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) + { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) + { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + /* write real header */ + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; + mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, + 0x0a, 0x1a, 0x0a, 0x00, 0x00, + 0x00, 0x0d, 0x49, 0x48, 0x44, + 0x52, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x49, 0x44, 0x41, + 0x54 }; + pnghdr[18] = (mz_uint8)(w >> 8); + pnghdr[19] = (mz_uint8)w; + pnghdr[22] = (mz_uint8)(h >> 8); + pnghdr[23] = (mz_uint8)h; + pnghdr[25] = chans[num_chans]; + pnghdr[33] = (mz_uint8)(*pLen_out >> 24); + pnghdr[34] = (mz_uint8)(*pLen_out >> 16); + pnghdr[35] = (mz_uint8)(*pLen_out >> 8); + pnghdr[36] = (mz_uint8)*pLen_out; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + /* write footer (IDAT CRC-32, followed by IEND chunk) */ + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) + { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + /* compute final size of file, grab compressed data buffer and return */ + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; +} +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +{ + /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +} + +/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ +/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +tdefl_compressor *tdefl_compressor_alloc() +{ + return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); +} + +void tdefl_compressor_free(tdefl_compressor *pComp) +{ + MZ_FREE(pComp); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#ifdef __cplusplus +} +#endif +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- Low-level Decompression (completely independent from all compression API's) */ + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) \ + { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do \ + { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do \ + { \ + for (;;) \ + { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +#define TINFL_GET_BYTE(state_index, c) \ + do \ + { \ + while (pIn_buf_cur >= pIn_buf_end) \ + { \ + TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ + } \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do \ + { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do \ + { \ + if (num_bits < (mz_uint)(n)) \ + { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ +/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ +/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ +/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do \ + { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) \ + { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } \ + else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) \ + break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ +/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ +/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ +/* The slow path is only executed at the very end of the input buffer. */ +/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ +/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ + do \ + { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) \ + { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) \ + { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } \ + else \ + { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else \ + { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do \ + { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; + static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; + static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; + static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; + static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) + { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) + { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) + { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) + { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) + { + TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) + { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) + { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) + { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; + if (!code_size) + continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) + { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) + { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) + { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) + { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + else + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) + { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) + { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for (;;) + { + mz_uint8 *pSrc; + for (;;) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) + { + bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; + do + { + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) + break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) + { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) + { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + + /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ + TINFL_SKIP_BITS(32, num_bits & 7); + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); + MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ + + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + for (counter = 0; counter < 4; ++counter) + { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + + TINFL_CR_FINISH + +common_exit: + /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ + /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ + /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ + if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) + { + while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) + { + --pIn_buf_cur; + num_bits -= 8; + } + } + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +/* Higher level helper functions. */ +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for (;;) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) + break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) + new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for (;;) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +tinfl_decompressor *tinfl_decompressor_alloc() +{ + tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); + if (pDecomp) + tinfl_init(pDecomp); + return pDecomp; +} + +void tinfl_decompressor_free(tinfl_decompressor *pDecomp) +{ + MZ_FREE(pDecomp); +} + +#ifdef __cplusplus +} +#endif +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * Copyright 2016 Martin Raiber + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- .ZIP archive reading */ + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include + +#if defined(_MSC_VER) || defined(__MINGW64__) +static FILE *mz_fopen(const char *pFilename, const char *pMode) +{ + FILE *pFile = NULL; + fopen_s(&pFile, pFilename, pMode); + return pFile; +} +static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) +{ + FILE *pFile = NULL; + if (freopen_s(&pFile, pPath, pMode, pStream)) + return NULL; + return pFile; +} +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove +#elif defined(__MINGW32__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__GNUC__) && _LARGEFILE64_SOURCE +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__APPLE__) && _LARGEFILE64_SOURCE +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen(p, m, s) +#define MZ_DELETE_FILE remove + +#else +#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#ifdef __STRICT_ANSI__ +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#else +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#endif +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif /* #ifdef _MSC_VER */ +#endif /* #ifdef MINIZ_NO_STDIO */ + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ +enum +{ + /* ZIP archive identifiers and record sizes */ + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + + /* ZIP64 archive identifier and record sizes */ + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, + MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, + MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, + MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, + MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, + + /* Central directory header record offsets */ + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + + /* Local directory header offsets */ + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, + + /* End of central directory offsets */ + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + + /* ZIP64 End of central directory locator offsets */ + MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ + MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ + + /* ZIP64 End of central directory header offsets */ + MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ + MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ + MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, + MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, + MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 +}; + +typedef struct +{ + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag +{ + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + + /* The flags passed in when the archive is initially opened. */ + uint32_t m_init_flags; + + /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ + mz_bool m_zip64; + + /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ + mz_bool m_zip64_has_extended_info_fields; + + /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ + MZ_FILE *m_pFile; + mz_uint64 m_file_archive_start_ofs; + + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size + +#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) +static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) +{ + MZ_ASSERT(index < pArray->m_size); + return index; +} +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] +#else +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +#endif + +static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) +{ + memset(pArray, 0, sizeof(mz_zip_array)); + pArray->m_element_size = element_size; +} + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) +{ + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) +{ + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) + return MZ_TRUE; + if (growing) + { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) + new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) +{ + if (new_capacity > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) + return MZ_FALSE; + } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) +{ + if (new_size > pArray->m_capacity) + { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) + return MZ_FALSE; + } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) +{ + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) +{ + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) + return MZ_FALSE; + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) +{ +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) + { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif /* #ifdef _MSC_VER */ + + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ + +#ifndef MINIZ_NO_STDIO +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) +{ + struct MZ_FILE_STAT_STRUCT file_stat; + + /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) + return MZ_FALSE; + + *pTime = file_stat.st_mtime; + + return MZ_TRUE; +} +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) +{ + struct utimbuf t; + + memset(&t, 0, sizeof(t)); + t.actime = access_time; + t.modtime = modified_time; + + return !utime(pFilename, &t); +} +#endif /* #ifndef MINIZ_NO_STDIO */ +#endif /* #ifndef MINIZ_NO_TIME */ + +static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) +{ + if (pZip) + pZip->m_last_error = err_num; + return MZ_FALSE; +} + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) +{ + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!pZip->m_pAlloc) + pZip->m_pAlloc = miniz_def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = miniz_def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = miniz_def_realloc_func; + + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + pZip->m_last_error = MZ_ZIP_NO_ERROR; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + pZip->m_pState->m_init_flags = flags; + pZip->m_pState->m_zip64 = MZ_FALSE; + pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) \ + do \ + { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END + +/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ +static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices; + mz_uint32 start, end; + const mz_uint32 size = pZip->m_total_files; + + if (size <= 1U) + return; + + pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + + start = (size - 2U) >> 1U; + for (;;) + { + mz_uint64 child, root = start; + for (;;) + { + if ((child = (root << 1U) + 1U) >= size) + break; + child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + if (!start) + break; + start--; + } + + end = size - 1; + while (end > 0) + { + mz_uint64 child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for (;;) + { + if ((child = (root << 1U) + 1U) >= end) + break; + child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) +{ + mz_int64 cur_file_ofs; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + + /* Basic sanity checks - reject files which are too small */ + if (pZip->m_archive_size < record_size) + return MZ_FALSE; + + /* Find the record by scanning the file from the end towards the beginning. */ + cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (;;) + { + int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + + for (i = n - 4; i >= 0; --i) + { + mz_uint s = MZ_READ_LE32(pBuf + i); + if (s == record_sig) + { + if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) + break; + } + } + + if (i >= 0) + { + cur_file_ofs += i; + break; + } + + /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) + return MZ_FALSE; + + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + + *pOfs = cur_file_ofs; + return MZ_TRUE; +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) +{ + mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; + mz_uint64 cdir_ofs = 0; + mz_int64 cur_file_ofs = 0; + const mz_uint8 *p; + + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; + + mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; + + mz_uint64 zip64_end_of_central_dir_ofs = 0; + + /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) + return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + + /* Read and verify the end of central directory record. */ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + { + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + { + if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) + { + zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); + if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + { + if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) + { + pZip->m_pState->m_zip64 = MZ_TRUE; + } + } + } + } + } + + pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); + cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + + if (pZip->m_pState->m_zip64) + { + mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); + mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); + mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); + mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); + mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); + + if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (zip64_total_num_of_disks != 1U) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + /* Check for miniz's practical limits */ + if (zip64_cdir_total_entries > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; + + if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; + + /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ + if (zip64_size_of_central_directory > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + cdir_size = (mz_uint32)zip64_size_of_central_directory; + + num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); + + cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); + + cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); + } + + if (pZip->m_total_files != cdir_entries_on_this_disk) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) + { + mz_uint i, n; + /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (sort_central_dir) + { + if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + /* Now create an index into the central directory file records, do some basic sanity checking on each record */ + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) + { + mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; + mz_uint64 comp_size, decomp_size, local_header_ofs; + + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + + if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && + (ext_data_size) && + (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) + { + /* Attempt to find zip64 extended information field in the entry's extra data */ + mz_uint32 extra_size_remaining = ext_data_size; + + if (extra_size_remaining) + { + const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; + + do + { + mz_uint32 field_id; + mz_uint32 field_data_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + + if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ + pZip->m_pState->m_zip64 = MZ_TRUE; + pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; + break; + } + + pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; + extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; + } while (extra_size_remaining); + } + } + + /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ + if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) + { + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); + + if (comp_size != MZ_UINT32_MAX) + { + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + n -= total_header_size; + p += total_header_size; + } + } + + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +void mz_zip_zero_struct(mz_zip_archive *pZip) +{ + if (pZip) + MZ_CLEAR_OBJ(*pZip); +} + +static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +{ + mz_bool status = MZ_TRUE; + + if (!pZip) + return MZ_FALSE; + + if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + { + if (set_last_error) + pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; + + return MZ_FALSE; + } + + if (pZip->m_pState) + { + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (MZ_FCLOSE(pState->m_pFile) == EOF) + { + if (set_last_error) + pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; + status = MZ_FALSE; + } + } + pState->m_pFile = NULL; + } +#endif /* #ifndef MINIZ_NO_STDIO */ + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return status; +} + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) +{ + return mz_zip_reader_end_internal(pZip, MZ_TRUE); +} +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) +{ + if ((!pZip) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_USER; + pZip->m_archive_size = size; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) +{ + if (!pMem) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pNeeds_keepalive = NULL; + +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + + pZip->m_pState->m_mem_size = size; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + + file_ofs += pZip->m_pState->m_file_archive_start_ofs; + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) +{ + return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); +} + +mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) +{ + mz_uint64 file_size; + MZ_FILE *pFile; + + if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + file_size = archive_size; + if (!file_size) + { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + { + MZ_FCLOSE(pFile); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + } + + file_size = MZ_FTELL64(pFile); + } + + /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ + + if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_init_internal(pZip, flags)) + { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + + pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) +{ + mz_uint64 cur_file_ofs; + + if ((!pZip) || (!pFile)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + cur_file_ofs = MZ_FTELL64(pFile); + + if (!archive_size) + { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + + archive_size = MZ_FTELL64(pFile) - cur_file_ofs; + + if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } + + if (!mz_zip_reader_init_internal(pZip, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = archive_size; + pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; + + if (!mz_zip_reader_read_central_dir(pZip, flags)) + { + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +#endif /* #ifndef MINIZ_NO_STDIO */ + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) +{ + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; +} + +mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint bit_flag; + mz_uint method; + + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); + bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + + if ((method != 0) && (method != MZ_DEFLATED)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + return MZ_FALSE; + } + + if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + return MZ_FALSE; + } + + if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) +{ + mz_uint filename_len, attribute_mapping_id, external_attr; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) + { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ + /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ + /* FIXME: Remove this check? Is it necessary - we already check the filename. */ + attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; + (void)attribute_mapping_id; + + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) + { + return MZ_TRUE; + } + + return MZ_FALSE; +} + +static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) +{ + mz_uint n; + const mz_uint8 *p = pCentral_dir_header; + + if (pFound_zip64_extra_data) + *pFound_zip64_extra_data = MZ_FALSE; + + if ((!p) || (!pStat)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Extract fields from the central directory record. */ + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + /* Copy as much of the filename and comment as possible. */ + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); + pStat->m_comment[n] = '\0'; + + /* Set some flags for convienance */ + pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); + pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); + pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); + + /* See if we need to read any zip64 extended information fields. */ + /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ + if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) + { + /* Attempt to find zip64 extended information field in the entry's extra data */ + mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); + + if (extra_size_remaining) + { + const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + + do + { + mz_uint32 field_id; + mz_uint32 field_data_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + + if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; + mz_uint32 field_data_remaining = field_data_size; + + if (pFound_zip64_extra_data) + *pFound_zip64_extra_data = MZ_TRUE; + + if (pStat->m_uncomp_size == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_uncomp_size = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + if (pStat->m_comp_size == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_comp_size = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + if (pStat->m_local_header_ofs == MZ_UINT32_MAX) + { + if (field_data_remaining < sizeof(mz_uint64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); + pField_data += sizeof(mz_uint64); + field_data_remaining -= sizeof(mz_uint64); + } + + break; + } + + pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; + extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; + } while (extra_size_remaining); + } + } + + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) +{ + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) + return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) + return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) +{ + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) + { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) + break; + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) +{ + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const uint32_t size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + + if (pIndex) + *pIndex = 0; + + if (size) + { + /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ + /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ + mz_int64 l = 0, h = (mz_int64)size - 1; + + while (l <= h) + { + mz_int64 m = l + ((h - l) >> 1); + uint32_t file_index = pIndices[(uint32_t)m]; + + int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + if (!comp) + { + if (pIndex) + *pIndex = file_index; + return MZ_TRUE; + } + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + } + + return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) +{ + mz_uint32 index; + if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) + return -1; + else + return (int)index; +} + +mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) +{ + mz_uint file_index; + size_t name_len, comment_len; + + if (pIndex) + *pIndex = 0; + + if ((!pZip) || (!pZip->m_pState) || (!pName)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* See if we can use a binary search */ + if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && + (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && + ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + { + return mz_zip_locate_file_binary_search(pZip, pName, pIndex); + } + + /* Locate the entry by scanning the entire central directory */ + name_len = strlen(pName); + if (name_len > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + for (file_index = 0; file_index < pZip->m_total_files; file_index++) + { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) + continue; + if (comment_len) + { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) + { + int ofs = filename_len - 1; + do + { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) + { + if (pIndex) + *pIndex = file_index; + return MZ_TRUE; + } + } + + return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + /* Ensure supplied output buffer is large enough. */ + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + if (buf_size < needed_size) + return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); + + /* Read and parse the local directory entry. */ + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data. */ + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) + { + if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) + return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); + } +#endif + + return MZ_TRUE; + } + + /* Decompress the file either directly from memory or from a file input buffer. */ + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) + { + /* Read directly from the archive in memory. */ + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else if (pUser_read_buf) + { + /* Use a user provided read buffer. */ + if (!user_read_buf_size) + return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + else + { + /* Temporarily allocate a read buffer. */ + read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do + { + /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ + size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + status = TINFL_STATUS_FAILED; + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (out_buf_ofs != file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); + status = TINFL_STATUS_FAILED; + } +#endif + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) +{ + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) +{ + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + void *pBuf; + + if (pSize) + *pSize = 0; + + if (!p) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return NULL; + } + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) + { + mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + return NULL; + } + + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return NULL; + } + + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) + *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + { + if (pSize) + *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + int status = TINFL_STATUS_DONE; + mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + /* Decompress the file either directly from memory or from a file input buffer. */ + if (pZip->m_pState->m_pMem) + { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data. */ + if (pZip->m_pState->m_pMem) + { + if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + } + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); +#endif + } + + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } + else + { + while (comp_remaining) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + } +#endif + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } + else + { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + status = TINFL_STATUS_FAILED; + } + else + { + do + { + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) + { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) + { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) + { + mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); +#endif + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (out_buf_ofs != file_stat.m_uncomp_size) + { + mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (file_crc32 != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); + status = TINFL_STATUS_FAILED; + } +#endif + } + + if (!pZip->m_pState->m_pMem) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + if (pWrite_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); +} + +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +{ + mz_zip_reader_extract_iter_state *pState; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + /* Argument sanity check */ + if ((!pZip) || (!pZip->m_pState)) + return NULL; + + /* Allocate an iterator status structure */ + pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); + if (!pState) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return NULL; + } + + /* Fetch file details */ + if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Encryption and patch files are not supported. */ + if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* This function only supports decompressing stored and deflate. */ + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) + { + mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Init state - save args */ + pState->pZip = pZip; + pState->flags = flags; + + /* Init state - reset variables to defaults */ + pState->status = TINFL_STATUS_DONE; +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + pState->file_crc32 = MZ_CRC32_INIT; +#endif + pState->read_buf_ofs = 0; + pState->out_buf_ofs = 0; + pState->pRead_buf = NULL; + pState->pWrite_buf = NULL; + pState->out_blk_remain = 0; + + /* Read and parse the local directory entry. */ + pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + + /* Decompress the file either directly from memory or from a file input buffer. */ + if (pZip->m_pState->m_pMem) + { + pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; + pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; + pState->comp_remaining = pState->file_stat.m_comp_size; + } + else + { + if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) + { + /* Decompression required, therefore intermediate read buffer required */ + pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + } + else + { + /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ + pState->read_buf_size = 0; + } + pState->read_buf_avail = 0; + pState->comp_remaining = pState->file_stat.m_comp_size; + } + + if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) + { + /* Decompression required, init decompressor */ + tinfl_init( &pState->inflator ); + + /* Allocate write buffer */ + if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + if (pState->pRead_buf) + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + return NULL; + } + } + + return pState; +} + +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +{ + mz_uint32 file_index; + + /* Locate file index by name */ + if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) + return NULL; + + /* Construct iterator */ + return mz_zip_reader_extract_iter_new(pZip, file_index, flags); +} + +size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) +{ + size_t copied_to_caller = 0; + + /* Argument sanity check */ + if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) + return 0; + + if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) + { + /* The file is stored or the caller has requested the compressed data, calc amount to return. */ + copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining ); + + /* Zip is in memory....or requires reading from a file? */ + if (pState->pZip->m_pState->m_pMem) + { + /* Copy data to caller's buffer */ + memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); + pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; + } + else + { + /* Read directly into caller's buffer */ + if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) + { + /* Failed to read all that was asked for, flag failure and alert user */ + mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); + pState->status = TINFL_STATUS_FAILED; + copied_to_caller = 0; + } + } + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + /* Compute CRC if not returning compressed data only */ + if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); +#endif + + /* Advance offsets, dec counters */ + pState->cur_file_ofs += copied_to_caller; + pState->out_buf_ofs += copied_to_caller; + pState->comp_remaining -= copied_to_caller; + } + else + { + do + { + /* Calc ptr to write buffer - given current output pos and block size */ + mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + + /* Calc max output size - given current output pos and block size */ + size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + + if (!pState->out_blk_remain) + { + /* Read more data from file if none available (and reading from file) */ + if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) + { + /* Calc read size */ + pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); + if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); + pState->status = TINFL_STATUS_FAILED; + break; + } + + /* Advance offsets, dec counters */ + pState->cur_file_ofs += pState->read_buf_avail; + pState->comp_remaining -= pState->read_buf_avail; + pState->read_buf_ofs = 0; + } + + /* Perform decompression */ + in_buf_size = (size_t)pState->read_buf_avail; + pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + pState->read_buf_avail -= in_buf_size; + pState->read_buf_ofs += in_buf_size; + + /* Update current output block size remaining */ + pState->out_blk_remain = out_buf_size; + } + + if (pState->out_blk_remain) + { + /* Calc amount to return. */ + size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); + + /* Copy data to caller's buffer */ + memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); + +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + /* Perform CRC */ + pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); +#endif + + /* Decrement data consumed from block */ + pState->out_blk_remain -= to_copy; + + /* Inc output offset, while performing sanity check */ + if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); + pState->status = TINFL_STATUS_FAILED; + break; + } + + /* Increment counter of data copied to caller */ + copied_to_caller += to_copy; + } + } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); + } + + /* Return how many bytes were copied into user buffer */ + return copied_to_caller; +} + +mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) +{ + int status; + + /* Argument sanity check */ + if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) + return MZ_FALSE; + + /* Was decompression completed and requested? */ + if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + { + /* Make sure the entire file was decompressed, and check its CRC. */ + if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); + pState->status = TINFL_STATUS_FAILED; + } +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + else if (pState->file_crc32 != pState->file_stat.m_crc32) + { + mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); + pState->status = TINFL_STATUS_FAILED; + } +#endif + } + + /* Free buffers */ + if (!pState->pZip->m_pState->m_pMem) + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); + if (pState->pWrite_buf) + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); + + /* Save status */ + status = pState->status; + + /* Free context */ + pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); + + return status == TINFL_STATUS_DONE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) +{ + (void)ofs; + + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) +{ + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + + if (MZ_FCLOSE(pFile) == EOF) + { + if (status) + mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + + status = MZ_FALSE; + } + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + + return status; +} + +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} + +mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) + return MZ_FALSE; + + if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); +} + +mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) +{ + mz_uint32 file_index; + if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) + return MZ_FALSE; + + return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_uint32 *p = (mz_uint32 *)pOpaque; + (void)file_ofs; + *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); + return n; +} + +mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) +{ + mz_zip_archive_file_stat file_stat; + mz_zip_internal_state *pState; + const mz_uint8 *pCentral_dir_header; + mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; + mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint64 local_header_ofs = 0; + mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; + mz_uint64 local_header_comp_size, local_header_uncomp_size; + mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; + mz_bool has_data_descriptor; + mz_uint32 local_header_bit_flags; + + mz_zip_array file_data_array; + mz_zip_array_init(&file_data_array, 1); + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (file_index > pZip->m_total_files) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); + + if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) + return MZ_FALSE; + + /* A directory or zero length file */ + if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) + return MZ_TRUE; + + /* Encryption and patch files are not supported. */ + if (file_stat.m_is_encrypted) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); + + /* This function only supports stored and deflate. */ + if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); + + if (!file_stat.m_is_supported) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); + + /* Read and parse the local directory entry. */ + local_header_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); + local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); + local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); + local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); + local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + has_data_descriptor = (local_header_bit_flags & 8) != 0; + + if (local_header_filename_len != strlen(file_stat.m_filename)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (local_header_filename_len) + { + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ + if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + + if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) + { + mz_uint32 extra_size_remaining = local_header_extra_len; + const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; + + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + goto handle_failure; + } + + local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); + local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + } + + /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ + /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ + if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) + { + mz_uint8 descriptor_buf[32]; + mz_bool has_id; + const mz_uint8 *pSrc; + mz_uint32 file_crc32; + mz_uint64 comp_size = 0, uncomp_size = 0; + + mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; + + if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + goto handle_failure; + } + + has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; + + file_crc32 = MZ_READ_LE32(pSrc); + + if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) + { + comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); + uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); + } + else + { + comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); + uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); + } + + if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + else + { + if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + goto handle_failure; + } + } + + mz_zip_array_clear(pZip, &file_data_array); + + if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) + { + if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) + return MZ_FALSE; + + /* 1 more check to be sure, although the extract checks too. */ + if (uncomp_crc32 != file_stat.m_crc32) + { + mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + return MZ_FALSE; + } + } + + return MZ_TRUE; + +handle_failure: + mz_zip_array_clear(pZip, &file_data_array); + return MZ_FALSE; +} + +mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) +{ + mz_zip_internal_state *pState; + uint32_t i; + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + /* Basic sanity checks */ + if (!pState->m_zip64) + { + if (pZip->m_total_files > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (pZip->m_archive_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + else + { + if (pZip->m_total_files >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + + for (i = 0; i < pZip->m_total_files; i++) + { + if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) + { + mz_uint32 found_index; + mz_zip_archive_file_stat stat; + + if (!mz_zip_reader_file_stat(pZip, i, &stat)) + return MZ_FALSE; + + if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) + return MZ_FALSE; + + /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ + if (found_index != i) + return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); + } + + if (!mz_zip_validate_file(pZip, i, flags)) + return MZ_FALSE; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) +{ + mz_bool success = MZ_TRUE; + mz_zip_archive zip; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + if ((!pMem) || (!size)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + mz_zip_zero_struct(&zip); + + if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) + { + if (pErr) + *pErr = zip.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_validate_archive(&zip, flags)) + { + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (!mz_zip_reader_end_internal(&zip, success)) + { + if (!actual_err) + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (pErr) + *pErr = actual_err; + + return success; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) +{ + mz_bool success = MZ_TRUE; + mz_zip_archive zip; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + if (!pFilename) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + mz_zip_zero_struct(&zip); + + if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) + { + if (pErr) + *pErr = zip.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_validate_archive(&zip, flags)) + { + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (!mz_zip_reader_end_internal(&zip, success)) + { + if (!actual_err) + actual_err = zip.m_last_error; + success = MZ_FALSE; + } + + if (pErr) + *pErr = actual_err; + + return success; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +/* ------------------- .ZIP archive writing */ + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} +static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) +{ + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} +static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) +{ + mz_write_le32(p, (mz_uint32)v); + mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); +} + +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) +#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); + + if (!n) + return 0; + + /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ + if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + return 0; + } + + if (new_size > pState->m_mem_capacity) + { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + + while (new_capacity < new_size) + new_capacity *= 2; + + if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + { + mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + return 0; + } + + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) +{ + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + { + if (set_last_error) + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return MZ_FALSE; + } + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) + { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (MZ_FCLOSE(pState->m_pFile) == EOF) + { + if (set_last_error) + mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); + status = MZ_FALSE; + } + } + + pState->m_pFile = NULL; + } +#endif /* #ifndef MINIZ_NO_STDIO */ + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) +{ + mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; + + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + { + if (!pZip->m_pRead) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + if (pZip->m_file_offset_alignment) + { + /* Ensure user specified file offset alignment is a power of 2. */ + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + if (!pZip->m_pAlloc) + pZip->m_pAlloc = miniz_def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = miniz_def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = miniz_def_realloc_func; + + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + + pZip->m_pState->m_zip64 = zip64; + pZip->m_pState->m_zip64_has_extended_info_fields = zip64; + + pZip->m_zip_type = MZ_ZIP_TYPE_USER; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) +{ + return mz_zip_writer_init_v2(pZip, existing_size, 0); +} + +mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) +{ + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_mem_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) + return MZ_FALSE; + + pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; + + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) + { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) + { + mz_zip_writer_end_internal(pZip, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) +{ + return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) +{ + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + + file_ofs += pZip->m_pState->m_file_archive_start_ofs; + + if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); + return 0; + } + + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) +{ + return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); +} + +mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) +{ + MZ_FILE *pFile; + + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) + return MZ_FALSE; + + if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) + { + mz_zip_writer_end(pZip); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + } + + pZip->m_pState->m_pFile = pFile; + pZip->m_zip_type = MZ_ZIP_TYPE_FILE; + + if (size_to_reserve_at_beginning) + { + mz_uint64 cur_ofs = 0; + char buf[4096]; + + MZ_CLEAR_OBJ(buf); + + do + { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) + { + mz_zip_writer_end(pZip); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) +{ + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; + + if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) + pZip->m_pRead = mz_zip_file_read_func; + + pZip->m_pIO_opaque = pZip; + + if (!mz_zip_writer_init_v2(pZip, 0, flags)) + return MZ_FALSE; + + pZip->m_pState->m_pFile = pFile; + pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; + + return MZ_TRUE; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) +{ + mz_zip_internal_state *pState; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) + { + /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ + if (!pZip->m_pState->m_zip64) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + /* No sense in trying to write to an archive that's already at the support max size */ + if (pZip->m_pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + + if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + } + + pState = pZip->m_pState; + + if (pState->m_pFile) + { +#ifdef MINIZ_NO_STDIO + (void)pFilename; + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); +#else + if (pZip->m_pIO_opaque != pZip) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) + { + if (!pFilename) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ + if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) + { + /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ + mz_zip_reader_end_internal(pZip, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + } + } + + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pNeeds_keepalive = NULL; +#endif /* #ifdef MINIZ_NO_STDIO */ + } + else if (pState->m_pMem) + { + /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ + if (pZip->m_pIO_opaque != pZip) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pNeeds_keepalive = NULL; + } + /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ + else if (!pZip->m_pWrite) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Start writing new files at the archive's current central directory location. */ + /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_central_directory_file_ofs = 0; + + /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ + /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ + /* TODO: We could easily maintain the sorted central directory offsets. */ + mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) +{ + return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); +} + +/* TODO: pArchive_name is a terrible name here! */ +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) +{ + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +} + +typedef struct +{ + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) +{ + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + return MZ_FALSE; + + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) +#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) +static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) +{ + mz_uint8 *pDst = pBuf; + mz_uint32 field_size = 0; + + MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); + MZ_WRITE_LE16(pDst + 2, 0); + pDst += sizeof(mz_uint16) * 2; + + if (pUncomp_size) + { + MZ_WRITE_LE64(pDst, *pUncomp_size); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + if (pComp_size) + { + MZ_WRITE_LE64(pDst, *pComp_size); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + if (pLocal_header_ofs) + { + MZ_WRITE_LE64(pDst, *pLocal_header_ofs); + pDst += sizeof(mz_uint64); + field_size += sizeof(mz_uint64); + } + + MZ_WRITE_LE16(pBuf + 2, field_size); + + return (mz_uint32)(pDst - pBuf); +} + +static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, + mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, + mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) +{ + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, + const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, + mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, + mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes, + const char *user_extra_data, mz_uint user_extra_data_len) +{ + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + if (!pZip->m_pState->m_zip64) + { + if (local_header_ofs > 0xFFFFFFFF) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); + } + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) + { + /* Try to resize the central directory array back into its original state. */ + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) +{ + /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ + if (*pArchive_name == '/') + return MZ_FALSE; + + while (*pArchive_name) + { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) + return MZ_FALSE; + + pArchive_name++; + } + + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) +{ + mz_uint32 n; + if (!pZip->m_file_offset_alignment) + return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) +{ + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) + { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) +{ + return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); +} + +mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + mz_uint8 *pExtra_data = NULL; + mz_uint32 extra_size = 0; + mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; + mz_uint16 bit_flags = 0; + + if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) + bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) + bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if (pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ + } + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + +#ifndef MINIZ_NO_TIME + if (last_modified != NULL) + { + mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); + } + else + { + MZ_TIME_T cur_time; + time(&cur_time); + mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif /* #ifndef MINIZ_NO_TIME */ + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!pState->m_zip64) + { + /* Bail early if the archive would obviously become too large */ + if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len + + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) + { + /* Set DOS Subdirectory attribute bit. */ + ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; + + /* Subdirectories cannot contain data. */ + if ((buf_size) || (uncomp_size)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + } + + /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if ((!store_data_uncompressed) && (buf_size)) + { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + cur_archive_file_ofs += num_alignment_padding_bytes; + + MZ_CLEAR_OBJ(local_dir_header); + + if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + method = MZ_DEFLATED; + } + + if (pState->m_zip64) + { + if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + { + pExtra_data = extra_data; + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_archive_file_ofs += archive_name_size; + + if (pExtra_data != NULL) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += extra_size; + } + } + else + { + if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_archive_file_ofs += archive_name_size; + } + + if (user_extra_data_len > 0) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += user_extra_data_len; + } + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + { + uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) + { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + if (store_data_uncompressed) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + } + else if (buf_size) + { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + if (uncomp_size) + { + mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; + mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + + MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); + + MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); + MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); + if (pExtra_data == NULL) + { + if (comp_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(local_dir_footer + 8, comp_size); + MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); + } + else + { + MZ_WRITE_LE64(local_dir_footer + 8, comp_size); + MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); + local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) + return MZ_FALSE; + + cur_archive_file_ofs += local_dir_footer_size; + } + + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, + user_extra_data_central, user_extra_data_central_len)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) +{ + mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + mz_uint8 *pExtra_data = NULL; + mz_uint32 extra_size = 0; + mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; + mz_zip_internal_state *pState; + + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) + gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + /* Sanity checks */ + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) + { + /* Source file is too large for non-zip64 */ + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + pState->m_zip64 = MZ_TRUE; + } + + /* We could support this, but why? */ + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + if (pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if (pZip->m_total_files == MZ_UINT16_MAX) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ + } + } + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ + if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + if (!pState->m_zip64) + { + /* Bail early if the archive would obviously become too large */ + if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 + + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) + { + pState->m_zip64 = MZ_TRUE; + /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ + } + } + +#ifndef MINIZ_NO_TIME + if (pFile_time) + { + mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); + } +#endif + + if (uncomp_size <= 3) + level = 0; + + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_archive_file_ofs; + + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + + if (uncomp_size && level) + { + method = MZ_DEFLATED; + } + + MZ_CLEAR_OBJ(local_dir_header); + if (pState->m_zip64) + { + if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) + { + pExtra_data = extra_data; + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += archive_name_size; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += extra_size; + } + else + { + if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += sizeof(local_dir_header); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) + { + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_archive_file_ofs += archive_name_size; + } + + if (user_extra_data_len > 0) + { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_archive_file_ofs += user_extra_data_len; + } + + if (uncomp_size) + { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) + { + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!level) + { + while (uncomp_remaining) + { + mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } + else + { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); + } + + for (;;) + { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + tdefl_flush flush = TDEFL_NO_FLUSH; + + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) + { + mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + break; + } + + uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + + if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) + flush = TDEFL_FULL_FLUSH; + + status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) + { + result = MZ_TRUE; + break; + } + else if (status != TDEFL_STATUS_OKAY) + { + mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); + break; + } + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + { + mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; + mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; + + MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); + MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); + if (pExtra_data == NULL) + { + if (comp_size > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(local_dir_footer + 8, comp_size); + MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); + } + else + { + MZ_WRITE_LE64(local_dir_footer + 8, comp_size); + MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); + local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) + return MZ_FALSE; + + cur_archive_file_ofs += local_dir_footer_size; + } + + if (pExtra_data != NULL) + { + extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, + (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); + } + + if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, + user_extra_data_central, user_extra_data_central_len)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + MZ_FILE *pSrc_file = NULL; + mz_uint64 uncomp_size = 0; + MZ_TIME_T file_modified_time; + MZ_TIME_T *pFile_time = NULL; + mz_bool status; + + memset(&file_modified_time, 0, sizeof(file_modified_time)); + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) + pFile_time = &file_modified_time; + if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); +#endif + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); + + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); + + MZ_FCLOSE(pSrc_file); + + return status; +} +#endif /* #ifndef MINIZ_NO_STDIO */ + +static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) +{ + /* + 64 should be enough for any new zip64 data */ + if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); + + if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) + { + mz_uint8 new_ext_block[64]; + mz_uint8 *pDst = new_ext_block; + mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); + mz_write_le16(pDst + sizeof(mz_uint16), 0); + pDst += sizeof(mz_uint16) * 2; + + if (pUncomp_size) + { + mz_write_le64(pDst, *pUncomp_size); + pDst += sizeof(mz_uint64); + } + + if (pComp_size) + { + mz_write_le64(pDst, *pComp_size); + pDst += sizeof(mz_uint64); + } + + if (pLocal_header_ofs) + { + mz_write_le64(pDst, *pLocal_header_ofs); + pDst += sizeof(mz_uint64); + } + + if (pDisk_start) + { + mz_write_le32(pDst, *pDisk_start); + pDst += sizeof(mz_uint32); + } + + mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); + + if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if ((pExt) && (ext_len)) + { + mz_uint32 extra_size_remaining = ext_len; + const mz_uint8 *pExtra_data = pExt; + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + } + + return MZ_TRUE; +} + +/* TODO: This func is now pretty freakin complex due to zip64, split it up? */ +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) +{ + mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; + mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; + const mz_uint8 *pSrc_central_header; + mz_zip_archive_file_stat src_file_stat; + mz_uint32 src_filename_len, src_comment_len, src_ext_len; + mz_uint32 local_header_filename_size, local_header_extra_len; + mz_uint64 local_header_comp_size, local_header_uncomp_size; + mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; + + /* Sanity checks */ + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ + if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + /* Get pointer to the source central dir header and crack it */ + if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); + src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); + src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; + + /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ + if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + + num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + if (!pState->m_zip64) + { + if (pZip->m_total_files == MZ_UINT16_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ + if (pZip->m_total_files == MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + + if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) + return MZ_FALSE; + + cur_src_file_ofs = src_file_stat.m_local_header_ofs; + cur_dst_file_ofs = pZip->m_archive_size; + + /* Read the source archive's local dir header */ + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + /* Compute the total size we need to copy (filename+extra data+compressed data) */ + local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); + local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); + local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); + src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; + + /* Try to find a zip64 extended information field */ + if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) + { + mz_zip_array file_data_array; + const mz_uint8 *pExtra_data; + mz_uint32 extra_size_remaining = local_header_extra_len; + + mz_zip_array_init(&file_data_array, 1); + if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) + { + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + pExtra_data = (const mz_uint8 *)file_data_array.m_p; + + do + { + mz_uint32 field_id, field_data_size, field_total_size; + + if (extra_size_remaining < (sizeof(mz_uint16) * 2)) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + field_id = MZ_READ_LE16(pExtra_data); + field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); + field_total_size = field_data_size + sizeof(mz_uint16) * 2; + + if (field_total_size > extra_size_remaining) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) + { + const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); + + if (field_data_size < sizeof(mz_uint64) * 2) + { + mz_zip_array_clear(pZip, &file_data_array); + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + } + + local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); + local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ + + found_zip64_ext_data_in_ldir = MZ_TRUE; + break; + } + + pExtra_data += field_total_size; + extra_size_remaining -= field_total_size; + } while (extra_size_remaining); + + mz_zip_array_clear(pZip, &file_data_array); + } + + if (!pState->m_zip64) + { + /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ + /* We also check when the archive is finalized so this doesn't need to be perfect. */ + mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + + pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; + + if (approx_new_archive_size >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + } + + /* Write dest archive padding */ + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + return MZ_FALSE; + + cur_dst_file_ofs += num_alignment_padding_bytes; + + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) + { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); + } + + /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ + if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + while (src_archive_bytes_remaining) + { + n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + cur_dst_file_ofs += n; + + src_archive_bytes_remaining -= n; + } + + /* Now deal with the optional data descriptor */ + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) + { + /* Copy data descriptor */ + if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) + { + /* src is zip64, dest must be zip64 */ + + /* name uint32_t's */ + /* id 1 (optional in zip64?) */ + /* crc 1 */ + /* comp_size 2 */ + /* uncomp_size 2 */ + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); + } + else + { + /* src is NOT zip64 */ + mz_bool has_id; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); + } + + has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); + + if (pZip->m_pState->m_zip64) + { + /* dest is zip64, so upgrade the data descriptor */ + const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); + const mz_uint32 src_crc32 = pSrc_descriptor[0]; + const mz_uint64 src_comp_size = pSrc_descriptor[1]; + const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; + + mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); + mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); + mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); + mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); + + n = sizeof(mz_uint32) * 6; + } + else + { + /* dest is NOT zip64, just copy it as-is */ + n = sizeof(mz_uint32) * (has_id ? 4 : 3); + } + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) + { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + /* Finally, add the new central dir header */ + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + + if (pState->m_zip64) + { + /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ + const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; + mz_zip_array new_ext_block; + + mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); + + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); + + if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) + { + mz_zip_array_clear(pZip, &new_ext_block); + return MZ_FALSE; + } + + MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + { + mz_zip_array_clear(pZip, &new_ext_block); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) + { + mz_zip_array_clear(pZip, &new_ext_block); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + mz_zip_array_clear(pZip, &new_ext_block); + } + else + { + /* sanity checks */ + if (cur_dst_file_ofs > MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + if (local_dir_header_ofs >= MZ_UINT32_MAX) + return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + + MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + } + + /* This shouldn't trigger unless we screwed up during the initial sanity checks */ + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) + { + /* TODO: Support central dirs >= 32-bits in size */ + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); + } + + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) + { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) +{ + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[256]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + pState = pZip->m_pState; + + if (pState->m_zip64) + { + if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + else + { + if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + } + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) + { + /* Write central directory */ + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += central_dir_size; + } + + if (pState->m_zip64) + { + /* Write zip64 end of central directory header */ + mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; + + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); + MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ + MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + + /* Write zip64 end of central directory locator */ + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); + MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); + MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + + pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; + } + + /* Write end of central directory record */ + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); + +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) + return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); +#endif /* #ifndef MINIZ_NO_STDIO */ + + pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) +{ + if ((!ppBuf) || (!pSize)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + *ppBuf = NULL; + *pSize = 0; + + if ((!pZip) || (!pZip->m_pState)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (pZip->m_pWrite != mz_zip_heap_write_func) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + if (!mz_zip_writer_finalize_archive(pZip)) + return MZ_FALSE; + + *ppBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) +{ + return mz_zip_writer_end_internal(pZip, MZ_TRUE); +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) +{ + return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); +} + +mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) +{ + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + mz_zip_error actual_err = MZ_ZIP_NO_ERROR; + + mz_zip_zero_struct(&zip_archive); + if ((int)level_and_flags < 0) + level_and_flags = MZ_DEFAULT_LEVEL; + + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + return MZ_FALSE; + } + + if (!mz_zip_writer_validate_archive_name(pArchive_name)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_FILENAME; + return MZ_FALSE; + } + + /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ + /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) + { + /* Create a new archive. */ + if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + return MZ_FALSE; + } + + created_new_archive = MZ_TRUE; + } + else + { + /* Append to an existing archive. */ + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + return MZ_FALSE; + } + + if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + + mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); + + return MZ_FALSE; + } + } + + status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); + actual_err = zip_archive.m_last_error; + + /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ + if (!mz_zip_writer_finalize_archive(&zip_archive)) + { + if (!actual_err) + actual_err = zip_archive.m_last_error; + + status = MZ_FALSE; + } + + if (!mz_zip_writer_end_internal(&zip_archive, status)) + { + if (!actual_err) + actual_err = zip_archive.m_last_error; + + status = MZ_FALSE; + } + + if ((!status) && (created_new_archive)) + { + /* It's a new archive and something went wrong, so just delete it. */ + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + + if (pErr) + *pErr = actual_err; + + return status; +} + +void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) +{ + mz_uint32 file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) + *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) + { + if (pErr) + *pErr = MZ_ZIP_INVALID_PARAMETER; + + return NULL; + } + + mz_zip_zero_struct(&zip_archive); + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) + { + if (pErr) + *pErr = zip_archive.m_last_error; + + return NULL; + } + + if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) + { + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + } + + mz_zip_reader_end_internal(&zip_archive, p != NULL); + + if (pErr) + *pErr = zip_archive.m_last_error; + + return p; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) +{ + return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); +} + +#endif /* #ifndef MINIZ_NO_STDIO */ + +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* ------------------- Misc utils */ + +mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; +} + +mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; +} + +mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) +{ + mz_zip_error prev_err; + + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + prev_err = pZip->m_last_error; + + pZip->m_last_error = err_num; + return prev_err; +} + +mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) +{ + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + return pZip->m_last_error; +} + +mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) +{ + return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); +} + +mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) +{ + mz_zip_error prev_err; + + if (!pZip) + return MZ_ZIP_INVALID_PARAMETER; + + prev_err = pZip->m_last_error; + + pZip->m_last_error = MZ_ZIP_NO_ERROR; + return prev_err; +} + +const char *mz_zip_get_error_string(mz_zip_error mz_err) +{ + switch (mz_err) + { + case MZ_ZIP_NO_ERROR: + return "no error"; + case MZ_ZIP_UNDEFINED_ERROR: + return "undefined error"; + case MZ_ZIP_TOO_MANY_FILES: + return "too many files"; + case MZ_ZIP_FILE_TOO_LARGE: + return "file too large"; + case MZ_ZIP_UNSUPPORTED_METHOD: + return "unsupported method"; + case MZ_ZIP_UNSUPPORTED_ENCRYPTION: + return "unsupported encryption"; + case MZ_ZIP_UNSUPPORTED_FEATURE: + return "unsupported feature"; + case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: + return "failed finding central directory"; + case MZ_ZIP_NOT_AN_ARCHIVE: + return "not a ZIP archive"; + case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: + return "invalid header or archive is corrupted"; + case MZ_ZIP_UNSUPPORTED_MULTIDISK: + return "unsupported multidisk archive"; + case MZ_ZIP_DECOMPRESSION_FAILED: + return "decompression failed or archive is corrupted"; + case MZ_ZIP_COMPRESSION_FAILED: + return "compression failed"; + case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: + return "unexpected decompressed size"; + case MZ_ZIP_CRC_CHECK_FAILED: + return "CRC-32 check failed"; + case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: + return "unsupported central directory size"; + case MZ_ZIP_ALLOC_FAILED: + return "allocation failed"; + case MZ_ZIP_FILE_OPEN_FAILED: + return "file open failed"; + case MZ_ZIP_FILE_CREATE_FAILED: + return "file create failed"; + case MZ_ZIP_FILE_WRITE_FAILED: + return "file write failed"; + case MZ_ZIP_FILE_READ_FAILED: + return "file read failed"; + case MZ_ZIP_FILE_CLOSE_FAILED: + return "file close failed"; + case MZ_ZIP_FILE_SEEK_FAILED: + return "file seek failed"; + case MZ_ZIP_FILE_STAT_FAILED: + return "file stat failed"; + case MZ_ZIP_INVALID_PARAMETER: + return "invalid parameter"; + case MZ_ZIP_INVALID_FILENAME: + return "invalid filename"; + case MZ_ZIP_BUF_TOO_SMALL: + return "buffer too small"; + case MZ_ZIP_INTERNAL_ERROR: + return "internal error"; + case MZ_ZIP_FILE_NOT_FOUND: + return "file not found"; + case MZ_ZIP_ARCHIVE_TOO_LARGE: + return "archive is too large"; + case MZ_ZIP_VALIDATION_FAILED: + return "validation failed"; + case MZ_ZIP_WRITE_CALLBACK_FAILED: + return "write calledback failed"; + default: + break; + } + + return "unknown error"; +} + +/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ +mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return MZ_FALSE; + + return pZip->m_pState->m_zip64; +} + +size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + + return pZip->m_pState->m_central_dir.m_size; +} + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) +{ + return pZip ? pZip->m_total_files : 0; +} + +mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) +{ + if (!pZip) + return 0; + return pZip->m_archive_size; +} + +mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + return pZip->m_pState->m_file_archive_start_ofs; +} + +MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) +{ + if ((!pZip) || (!pZip->m_pState)) + return 0; + return pZip->m_pState->m_pFile; +} + +size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) +{ + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + + return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) +{ + mz_uint n; + const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); + if (!p) + { + if (filename_buf_size) + pFilename[0] = '\0'; + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) + { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) +{ + return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); +} + +mz_bool mz_zip_end(mz_zip_archive *pZip) +{ + if (!pZip) + return MZ_FALSE; + + if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) + return mz_zip_reader_end(pZip); +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) + return mz_zip_writer_end(pZip); +#endif + + return MZ_FALSE; +} + +#ifdef __cplusplus +} +#endif + +#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.h new file mode 100644 index 0000000..86fac4c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.h @@ -0,0 +1,1328 @@ +/* miniz.c 2.0.6 beta - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ +#pragma once + + + + + +/* Defines to completely disable specific portions of miniz.c: + If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ + +/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ +/*#define MINIZ_NO_STDIO */ + +/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ +/* get/set file times, and the C run-time funcs that get/set times won't be called. */ +/* The current downside is the times written to your archives will be from 1979. */ +/*#define MINIZ_NO_TIME */ + +/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_APIS */ + +/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ +/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ + +/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ +/*#define MINIZ_NO_ZLIB_APIS */ + +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ +/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. + Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc + callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user + functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ +/*#define MINIZ_NO_MALLOC */ + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ +#define MINIZ_NO_TIME +#endif + +#include + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ +#define MINIZ_X86_OR_X64_CPU 1 +#else +#define MINIZ_X86_OR_X64_CPU 0 +#endif + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ +#define MINIZ_LITTLE_ENDIAN 1 +#else +#define MINIZ_LITTLE_ENDIAN 0 +#endif + +#if MINIZ_X86_OR_X64_CPU +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#else +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) +/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ +#define MINIZ_HAS_64BIT_REGISTERS 1 +#else +#define MINIZ_HAS_64BIT_REGISTERS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------- zlib-style API Definitions. */ + +/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ +typedef unsigned long mz_ulong; + +/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ +void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +/* Compression strategies. */ +enum +{ + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +/* Method */ +#define MZ_DEFLATED 8 + +/* Heap allocation callbacks. +Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ +enum +{ + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +#define MZ_VERSION "10.0.1" +#define MZ_VERNUM 0xA010 +#define MZ_VER_MAJOR 10 +#define MZ_VER_MINOR 0 +#define MZ_VER_REVISION 1 +#define MZ_VER_SUBREVISION 0 + +#ifndef MINIZ_NO_ZLIB_APIS + +/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ +enum +{ + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +/* Return status codes. MZ_PARAM_ERROR is non-standard. */ +enum +{ + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +/* Window bits */ +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +/* Compression/decompression stream struct. */ +typedef struct mz_stream_s +{ + const unsigned char *next_in; /* pointer to next byte to read */ + unsigned int avail_in; /* number of bytes available at next_in */ + mz_ulong total_in; /* total number of bytes consumed so far */ + + unsigned char *next_out; /* pointer to next byte to write */ + unsigned int avail_out; /* number of bytes that can be written to next_out */ + mz_ulong total_out; /* total number of bytes produced so far */ + + char *msg; /* error msg (unused) */ + struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ + + mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ + mz_free_func zfree; /* optional heap free function (defaults to free) */ + void *opaque; /* heap alloc function user pointer */ + + int data_type; /* data_type (unused) */ + mz_ulong adler; /* adler32 of the source or uncompressed data */ + mz_ulong reserved; /* not used */ +} mz_stream; + +typedef mz_stream *mz_streamp; + +/* Returns the version string of miniz.c. */ +const char *mz_version(void); + +/* mz_deflateInit() initializes a compressor with default options: */ +/* Parameters: */ +/* pStream must point to an initialized mz_stream struct. */ +/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ +/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ +/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if the input parameters are bogus. */ +/* MZ_MEM_ERROR on out of memory. */ +int mz_deflateInit(mz_streamp pStream, int level); + +/* mz_deflateInit2() is like mz_deflate(), except with more control: */ +/* Additional parameters: */ +/* method must be MZ_DEFLATED */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ +/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +int mz_deflateReset(mz_streamp pStream); + +/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ +/* Return values: */ +/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ +/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ +int mz_deflate(mz_streamp pStream, int flush); + +/* mz_deflateEnd() deinitializes a compressor: */ +/* Return values: */ +/* MZ_OK on success. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +int mz_deflateEnd(mz_streamp pStream); + +/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +/* Single-call compression functions mz_compress() and mz_compress2(): */ +/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ +mz_ulong mz_compressBound(mz_ulong source_len); + +/* Initializes a decompressor. */ +int mz_inflateInit(mz_streamp pStream); + +/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ +/* Parameters: */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ +/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ +/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ +/* Return values: */ +/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ +/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ +/* MZ_STREAM_ERROR if the stream is bogus. */ +/* MZ_DATA_ERROR if the deflate stream is invalid. */ +/* MZ_PARAM_ERROR if one of the parameters is invalid. */ +/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ +/* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ +int mz_inflate(mz_streamp pStream, int flush); + +/* Deinitializes a decompressor. */ +int mz_inflateEnd(mz_streamp pStream); + +/* Single-call decompression. */ +/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + +/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ +const char *mz_error(int err); + +/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() +#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ + +#endif /* MINIZ_NO_ZLIB_APIS */ + +#ifdef __cplusplus +} +#endif +#pragma once +#include +#include +#include +#include + +/* ------------------- Types and macros */ +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef int64_t mz_int64; +typedef uint64_t mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#define MZ_FILE FILE +#endif /* #ifdef MINIZ_NO_STDIO */ + +#ifdef MINIZ_NO_TIME +typedef struct mz_dummy_time_t_tag +{ + int m_dummy; +} mz_dummy_time_t; +#define MZ_TIME_T mz_dummy_time_t +#else +#define MZ_TIME_T time_t +#endif + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); +extern void miniz_def_free_func(void *opaque, void *address); +extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); + +#define MZ_UINT16_MAX (0xFFFFU) +#define MZ_UINT32_MAX (0xFFFFFFFFU) + +#ifdef __cplusplus +} +#endif +#pragma once + + +#ifdef __cplusplus +extern "C" { +#endif +/* ------------------- Low-level Compression API Definitions */ + +/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ +#define TDEFL_LESS_MEMORY 0 + +/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ +/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ +enum +{ + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ +/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ +/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ +/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ +/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ +/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ +/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ +/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ +/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +/* High level compression functions: */ +/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ +/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must free() the returned block when it's no longer needed. */ +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ +/* Returns 0 on failure. */ +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* Compresses an image to a compressed PNG file in memory. */ +/* On entry: */ +/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ +/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ +/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ +/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ +/* On return: */ +/* Function returns a pointer to the compressed data, or NULL on failure. */ +/* *pLen_out will be set to the size of the PNG image file. */ +/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); + +/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum +{ + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ +#if TDEFL_LESS_MEMORY +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum +{ + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +/* tdefl's compression state structure. */ +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +/* Initializes the compressor. */ +/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ +/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ +/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ +/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ +/* tdefl_compress_buffer() always consumes the entire input buffer. */ +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +/* Create tdefl_compress() flags given zlib-style compression parameters. */ +/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ +/* window_bits may be -15 (raw deflate) or 15 (zlib) */ +/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); + +/* Allocate the tdefl_compressor structure in C so that */ +/* non-C language bindings to tdefl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ +tdefl_compressor *tdefl_compressor_alloc(); +void tdefl_compressor_free(tdefl_compressor *pComp); + +#ifdef __cplusplus +} +#endif +#pragma once + +/* ------------------- Low-level Decompression API Definitions */ + +#ifdef __cplusplus +extern "C" { +#endif +/* Decompression flags used by tinfl_decompress(). */ +/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ +/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ +/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ +/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +/* High level decompression functions: */ +/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ +/* On entry: */ +/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ +/* On return: */ +/* Function returns a pointer to the decompressed data, or NULL on failure. */ +/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ +/* The caller must call mz_free() on the returned block when it's no longer needed. */ +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ +/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ +/* Returns 1 on success or 0 on failure. */ +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +/* Allocate the tinfl_decompressor structure in C so that */ +/* non-C language bindings to tinfl_ API don't need to worry about */ +/* structure size and allocation mechanism. */ + +tinfl_decompressor *tinfl_decompressor_alloc(); +void tinfl_decompressor_free(tinfl_decompressor *pDecomp); + +/* Max size of LZ dictionary. */ +#define TINFL_LZ_DICT_SIZE 32768 + +/* Return status. */ +typedef enum { + /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ + /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ + /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ + TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, + + /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ + TINFL_STATUS_BAD_PARAM = -3, + + /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ + TINFL_STATUS_ADLER32_MISMATCH = -2, + + /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ + TINFL_STATUS_FAILED = -1, + + /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ + + /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ + /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ + TINFL_STATUS_DONE = 0, + + /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ + /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ + /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + + /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ + /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ + /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ + /* so I may need to add some code to address this. */ + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +/* Initializes the decompressor to its initial state. */ +#define tinfl_init(r) \ + do \ + { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ +/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +/* Internal/private bits follow. */ +enum +{ + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#else +#define TINFL_USE_64BIT_BITBUF 0 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#ifdef __cplusplus +} +#endif + +#pragma once + + +/* ------------------- ZIP archive reading/writing */ + +#ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 +}; + +typedef struct +{ + /* Central directory file index. */ + mz_uint32 m_file_index; + + /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ + mz_uint64 m_central_dir_ofs; + + /* These fields are copied directly from the zip's central dir. */ + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; + +#ifndef MINIZ_NO_TIME + MZ_TIME_T m_time; +#endif + + /* CRC-32 of uncompressed data. */ + mz_uint32 m_crc32; + + /* File's compressed size. */ + mz_uint64 m_comp_size; + + /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ + mz_uint64 m_uncomp_size; + + /* Zip internal and external file attributes. */ + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + + /* Entry's local header file offset in bytes. */ + mz_uint64 m_local_header_ofs; + + /* Size of comment in bytes. */ + mz_uint32 m_comment_size; + + /* MZ_TRUE if the entry appears to be a directory. */ + mz_bool m_is_directory; + + /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ + mz_bool m_is_encrypted; + + /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ + mz_bool m_is_supported; + + /* Filename. If string ends in '/' it's a subdirectory entry. */ + /* Guaranteed to be zero terminated, may be truncated to fit. */ + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + + /* Comment field. */ + /* Guaranteed to be zero terminated, may be truncated to fit. */ + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; + +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum { + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, + MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ + MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ + MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ + MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, + MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 +} mz_zip_flags; + +typedef enum { + MZ_ZIP_TYPE_INVALID = 0, + MZ_ZIP_TYPE_USER, + MZ_ZIP_TYPE_MEMORY, + MZ_ZIP_TYPE_HEAP, + MZ_ZIP_TYPE_FILE, + MZ_ZIP_TYPE_CFILE, + MZ_ZIP_TOTAL_TYPES +} mz_zip_type; + +/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ +typedef enum { + MZ_ZIP_NO_ERROR = 0, + MZ_ZIP_UNDEFINED_ERROR, + MZ_ZIP_TOO_MANY_FILES, + MZ_ZIP_FILE_TOO_LARGE, + MZ_ZIP_UNSUPPORTED_METHOD, + MZ_ZIP_UNSUPPORTED_ENCRYPTION, + MZ_ZIP_UNSUPPORTED_FEATURE, + MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, + MZ_ZIP_NOT_AN_ARCHIVE, + MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, + MZ_ZIP_UNSUPPORTED_MULTIDISK, + MZ_ZIP_DECOMPRESSION_FAILED, + MZ_ZIP_COMPRESSION_FAILED, + MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, + MZ_ZIP_CRC_CHECK_FAILED, + MZ_ZIP_UNSUPPORTED_CDIR_SIZE, + MZ_ZIP_ALLOC_FAILED, + MZ_ZIP_FILE_OPEN_FAILED, + MZ_ZIP_FILE_CREATE_FAILED, + MZ_ZIP_FILE_WRITE_FAILED, + MZ_ZIP_FILE_READ_FAILED, + MZ_ZIP_FILE_CLOSE_FAILED, + MZ_ZIP_FILE_SEEK_FAILED, + MZ_ZIP_FILE_STAT_FAILED, + MZ_ZIP_INVALID_PARAMETER, + MZ_ZIP_INVALID_FILENAME, + MZ_ZIP_BUF_TOO_SMALL, + MZ_ZIP_INTERNAL_ERROR, + MZ_ZIP_FILE_NOT_FOUND, + MZ_ZIP_ARCHIVE_TOO_LARGE, + MZ_ZIP_VALIDATION_FAILED, + MZ_ZIP_WRITE_CALLBACK_FAILED, + MZ_ZIP_TOTAL_ERRORS +} mz_zip_error; + +typedef struct +{ + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + + /* We only support up to UINT32_MAX files in zip64 mode. */ + mz_uint32 m_total_files; + mz_zip_mode m_zip_mode; + mz_zip_type m_zip_type; + mz_zip_error m_last_error; + + mz_uint64 m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + mz_file_needs_keepalive m_pNeeds_keepalive; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef struct +{ + mz_zip_archive *pZip; + mz_uint flags; + + int status; +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + mz_uint file_crc32; +#endif + mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + void *pWrite_buf; + + size_t out_blk_remain; + + tinfl_decompressor inflator; + +} mz_zip_reader_extract_iter_state; + +/* -------- ZIP reading */ + +/* Inits a ZIP archive reader. */ +/* These functions read and validate the archive's central directory. */ +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +/* Read a archive from a disk file. */ +/* file_start_ofs is the file offset where the archive actually begins, or 0. */ +/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); + +/* Read an archive from an already opened FILE, beginning at the current file position. */ +/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ +/* The FILE will NOT be closed when mz_zip_reader_end() is called. */ +mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); +#endif + +/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ +mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +/* -------- ZIP reading or writing */ + +/* Clears a mz_zip_archive struct to all zeros. */ +/* Important: This must be done before passing the struct to any mz_zip functions. */ +void mz_zip_zero_struct(mz_zip_archive *pZip); + +mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); +mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); + +/* Returns the total number of files in the archive. */ +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); +mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); +MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); + +/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ +size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +/* Returns MZ_FALSE if the file cannot be found. */ +mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex); + +/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ +/* Note that the m_last_error functionality is not thread safe. */ +mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); +mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); +mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); +mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); +const char *mz_zip_get_error_string(mz_zip_error mz_err); + +/* MZ_TRUE if the archive file entry is a directory entry. */ +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the file is encrypted/strong encrypted. */ +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); + +/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ +mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); + +/* Retrieves the filename of an archive file entry. */ +/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); + +/* Attempts to locates a file in the archive's central directory. */ +/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ +/* Returns -1 if the file cannot be found. */ +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); + +/* Returns detailed information about an archive file entry. */ +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); + +/* MZ_TRUE if the file is in zip64 format. */ +/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ +mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); + +/* Returns the total central directory size in bytes. */ +/* The current max supported size is <= MZ_UINT32_MAX. */ +size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); + +/* Extracts a archive file to a memory buffer using no memory allocation. */ +/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +/* Extracts a archive file to a memory buffer. */ +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); + +/* Extracts a archive file to a dynamically allocated heap buffer. */ +/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ +/* Returns NULL and sets the last error on failure. */ +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); + +/* Extracts a archive file using a callback function to output the file's data. */ +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); + +/* Extract a file iteratively */ +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); +mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); +size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); +mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); + +#ifndef MINIZ_NO_STDIO +/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ +/* This function only extracts files, not archive directory records. */ +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); + +/* Extracts a archive file starting at the current position in the destination FILE stream. */ +mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); +#endif + +#if 0 +/* TODO */ + typedef void *mz_zip_streaming_extract_state_ptr; + mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); + size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); + mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); +#endif + +/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ +/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ +mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); + +/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ +mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); + +/* Misc utils/helpers, valid for ZIP reading or writing */ +mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); +mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); + +/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ +mz_bool mz_zip_end(mz_zip_archive *pZip); + +/* -------- ZIP writing */ + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +/* Inits a ZIP archive writer. */ +/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ +/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); +mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); +#endif + +/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ +/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ +/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ +/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ +/* the archive is finalized the file's central directory will be hosed. */ +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); + +/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ +/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ +/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); + +mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); + +#ifndef MINIZ_NO_STDIO +/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + +/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ +mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, + const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); +#endif + +/* Adds a file to an archive by fully cloning the data from another archive. */ +/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); + +/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ +/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ +/* An archive must be manually finalized by calling this function for it to be valid. */ +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); + +/* Finalizes a heap archive, returning a poiner to the heap block and its size. */ +/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); + +/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ +/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +/* -------- Misc. high-level helper functions: */ + +/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ +/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ +mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); + +/* Reads a single file from an archive into a heap block. */ +/* If pComment is not NULL, only the file with the specified comment will be extracted. */ +/* Returns NULL on failure. */ +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); +void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); + +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ + +#ifdef __cplusplus +} +#endif + +#endif /* MINIZ_NO_ARCHIVE_APIS */ diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/CSharpGenerator.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/CSharpGenerator.cpp new file mode 100644 index 0000000..348b0f4 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/CSharpGenerator.cpp @@ -0,0 +1,18 @@ +#include "CSharpGenerator.h" + +#include + +using std::endl; +using std::ostream; +using namespace mbientlab::cbinds; + +Generator* createCSharpGenerator() { + return new CSharpGenerator(); +} + +CSharpGenerator::~CSharpGenerator() { +} + +void CSharpGenerator::create(ostream& os, const CHeaderFile& header) { + os << "This is a csharp generator" << endl; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/CSharpGenerator.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/CSharpGenerator.h new file mode 100644 index 0000000..82985c5 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/CSharpGenerator.h @@ -0,0 +1,13 @@ +#pragma once + +#include "cbinds/Generator.h" +#include "metawear/platform/dllmarker.h" + +class CSharpGenerator : public mbientlab::cbinds::Generator { +public: + virtual ~CSharpGenerator(); + + virtual void create(std::ostream& os, const mbientlab::cbinds::CHeaderFile& header); +}; + +extern "C" METAWEAR_API mbientlab::cbinds::Generator* createCSharpGenerator(); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/JavaScriptGenerator.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/JavaScriptGenerator.cpp new file mode 100644 index 0000000..2037720 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/JavaScriptGenerator.cpp @@ -0,0 +1,292 @@ +#include "JavaScriptGenerator.h" +#include "cbinds/Util.h" +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using std::endl; +using std::function; +using std::isdigit; +using std::isupper; +using std::ostream; +using std::string; +using std::stringstream; +using std::toupper; +using std::unordered_map; +using std::unordered_set; + +using namespace mbientlab::cbinds; + +static const unordered_map FN_TYPE_NAME_MAPPING = { + { "float" , "Float" }, + { "void" , "Void" }, + { "int64_t" , "Long" }, + { "int32_t" , "Int" }, + { "int8_t" , "Byte" }, + { "uint8_t" , "UByte" }, + { "uint16_t" , "UShort" }, + { "uint32_t" , "UInt" }, + { "uint64_t" , "Ulong" } +}; + +Generator* createJavaScriptGenerator() { + return new JavaScriptGenerator(); +} + +JavaScriptGenerator::~JavaScriptGenerator() { + +} + +void JavaScriptGenerator::create(ostream& os, const CHeaderFile& header) { + unordered_set exports = { + "ArrayUByte_6", + "ArrayUByte_10", + "ArrayFloat", + "ArrayUByte_16", + "ArrayAnonymousDataSignalP", + "ArrayDataSignalP" + }; + unordered_map typeMapping = { + { "float" , "ref.types.float" }, + { "void" , "ref.types.void" }, + { "int64_t" , "ref.types.int64" }, + { "int32_t" , "ref.types.int32" }, + { "int8_t" , "ref.types.int8" }, + { "uint8_t" , "ref.types.uint8" }, + { "uint16_t" , "ref.types.uint16" }, + { "uint32_t" , "ref.types.uint32" }, + { "uint64_t" , "ref.types.uint64" } + }; + + os << "// Warning!!!" << endl + << "// This JavaScript module is generated from the MetaWear C++ API header files" << endl + << "// Do not edit" << endl + << "var ref = require('ref');" << endl + << "var ffi = require('ffi');" << endl + << "var Struct = require('ref-struct');" << endl + << "var ArrayType = require('ref-array');" << endl + << "var Enum = require('enum');" << endl + << "var LIBMETAWEAR_PATH = require('./libmetawear-path');" << endl << endl + << "// TODO: These exist because arrays are not handled perfectly yet" << endl + << "var ArrayUByte_6 = ArrayType(ref.types.uint8, 6);" << endl + << "var ArrayFloat = ArrayType(ref.types.float);" << endl + << "var ArrayUByte_10 = ArrayType(ref.types.uint8, 10);" << endl + << "var ArrayUByte_16 = ArrayType(ref.types.uint8, 16);" << endl << endl; + + for(auto& it: header.getEnums()) { + string prefix = createPrefix(it.first); + string stripType = strip(it.first, "MblMw"); + exports.insert(stripType); + os << "var " << stripType << " = new Enum({" << endl; + typeMapping.insert({it.first, stripType}); + bool first = true; + for(auto& entry: it.second->getEntries()) { + string stripped = strip(entry.name, prefix); + if (stripped == entry.name) { + stripped = strip(entry.name, SHORTENED_PREFIXES.at(it.first)); + } + if (isdigit(stripped[0])) { + stripped = "_" + stripped; + } + if (!first) { + os << "," << endl; + } + os << " '" << stripped << "': " << entry.value; + first = false; + } + os << endl << "}, ref.types.int);" << endl; + os << stripType << ".alignment = 4;" << endl << endl; + } + + unordered_set fnPtrs, structs, presetTypeNames; + auto convertFnTypeName = [&](const Type& type) -> string { + string stripped(strip(type.getName(), "MblMw")); + string name= FN_TYPE_NAME_MAPPING.count(stripped) ? FN_TYPE_NAME_MAPPING.at(stripped) : stripped; + if (type.isPointer()) { + name+= "P"; + } + return name; + }; + auto convertType = [&](const Type& type) -> string { + auto arraySize = type.getArraySize(); + if (type.isArray()) { + // only need array of native types for now + // will need to expand this if we do array of objects or pointers + stringstream result; + result << "Array" << FN_TYPE_NAME_MAPPING.at(type.getName()); + if (arraySize != -1) { + result << "_" << arraySize; + } + assert(exports.count(result.str()) && "New Array Type, add to list or generalize this code"); + return result.str(); + } else if (type.isPointer()) { + auto isFnPtr = dynamic_cast(&type) != nullptr; + if (header.getStructs().count(type.getName())) { + auto structObj = header.getStructs().at(type.getName()); + return "ref.refType(" + typeMapping.at(structObj->getName()) + ")"; + } else if (type.getName() == "char") { + return "ref.types.CString"; + } else if (typeMapping.count(type.getName()) && !isFnPtr) { + return "ref.refType(" + typeMapping.at(type.getName()) + ")"; + } else if (isFnPtr) { + return typeMapping.at(type.getName()); + } + return "ref.refType(ref.types.void)"; + } else { + return typeMapping.at(type.getName()); + } + }; + function printStruct; + function printFunctionPtr = [&](const FunctionPointer* fnPointer) -> void { + if (fnPtrs.count(fnPointer->getName())) { + return; + } + + string mappedName("Fn" + convertFnTypeName(*(fnPointer->getReturnType()))); + for(auto& param: fnPointer->getParameters()) { + auto& type = param->getType(); + + if (header.getStructs().count(type.getName())) { + printStruct(header.getStructs().at(type.getName())); + } + + mappedName+= "_" + convertFnTypeName(type); + } + + typeMapping.insert({fnPointer->getName(), mappedName}); + if (presetTypeNames.count(mappedName)) { + return; + } + presetTypeNames.insert(mappedName); + + exports.insert(mappedName); + os << "var " << mappedName << " = ffi.Function("; + os << convertType(*fnPointer->getReturnType()) << ", ["; + bool first = true; + for(auto& param: fnPointer->getParameters()) { + if (!first) { + os << ", "; + } + os << convertType(param->getType()); + first = false; + } + os << "]);" << endl; + fnPtrs.insert(fnPointer->getName()); + }; + printStruct = [&](const Struct* structObj) -> void { + if (structs.count(structObj->getName())) { + return; + } + + if (structObj->isForwardDecl()) { + string strippedName(strip(structObj->getName(), "MblMw")); + exports.insert(strippedName); + typeMapping.insert({structObj->getName(), strippedName}); + os << "var " << strippedName << " = ref.types.void;" << endl; + } else { + for(auto& field: structObj->getFields()) { + const FunctionPointer* fnPtr; + if ((fnPtr = dynamic_cast(&field->getType())) != nullptr) { + printFunctionPtr(fnPtr); + } + } + + string strippedName(strip(structObj->getName(), "MblMw")); + typeMapping.insert({structObj->getName(), strippedName}); + + bool first = true; + exports.insert(strippedName); + os << "var " << strippedName << " = Struct({" << endl; + for(auto field: structObj->getFields()) { + if (!first) { + os << "," << endl; + } + os << " '" << field->getName() << "': " << convertType(field->getType()); + first = false; + } + os << endl << "});" << endl << endl; + } + structs.insert(structObj->getName()); + }; + + for(auto it: header.getFunctionPointers()) { + printFunctionPtr(it.second); + } + + for(auto it: header.getStructs()) { + printStruct(it.second); + } + + exports.insert("Const"); + os << "function Const() {" << endl << "}" << endl; + for(auto it: header.getConstants()) { + if (header.getStructs().count(it.second->getType()->getName())) { + auto structObj = header.getStructs().at(it.second->getType()->getName()); + os << "Const." << strip(it.second->getName(), "MBL_MW_") << " = new " << typeMapping.at(it.second->getType()->getName()) << "({"; + + bool first = true; + for(size_t i = 0 ; i < structObj->getFields().size(); i++) { + if (!first) { + os << ", "; + } + os << structObj->getFields()[i]->getName() << ": " << it.second->getValueComponents()[i]; + first = false; + } + os << "})" << endl; + } else { + os << "Const." << strip(it.second->getName(), "MBL_MW_") << " = " << it.second->getValue() << ";" << endl; + } + } + os << endl; + + exports.insert("Lib"); + bool firstFunction = true; + os << "// TODO: This line exisits because the generator doesn't understand array of pointers" << endl; + os << "var ArrayAnonymousDataSignalP = ArrayType(ref.refType(AnonymousDataSignal));" << endl; + os << "FnVoid_VoidP_MetaWearBoardP_AnonymousDataSignalP_UInt = ffi.Function(ref.types.void, [ref.refType(ref.types.void), ref.refType(MetaWearBoard), ArrayAnonymousDataSignalP, ref.types.uint32]);" << endl; + os << "var ArrayDataSignalP = ArrayType(ref.refType(DataSignal));" << endl; + os << "var Lib = ffi.Library(LIBMETAWEAR_PATH, {" << endl; + for(auto it: header.getFunctions()) { + if (!firstFunction) { + os << "," << endl << endl; + } + os << it.second->getComment() << endl; + os << " '" << it.first << "': [" << convertType(*(it.second->getReturnType())) << ", ["; + + if (it.first == "mbl_mw_dataprocessor_fuser_create") { + // hardcode array type definition for fueser + // need to generalize array bindings for objects and pointers + os << "ref.refType(DataSignal), ArrayDataSignalP, ref.types.uint32, ref.refType(ref.types.void), FnVoid_VoidP_DataProcessorP]]"; + } else { + bool first = true; + for(auto param: it.second->getParameters()) { + if (!first) { + os << ", "; + } + os << convertType(param->getType()); + first = false; + } + os << "]]"; + } + firstFunction = false; + } + os << endl << "});" << endl << endl; + + bool first = true; + os << "module.exports = {" << endl; + for(auto& expor: exports) { + if (!first) { + os << "," << endl; + } + os << " " << expor << ": " << expor; + first = false; + } + os << endl << "};" << endl; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/JavaScriptGenerator.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/JavaScriptGenerator.h new file mode 100644 index 0000000..6ad5a75 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/JavaScriptGenerator.h @@ -0,0 +1,13 @@ +#pragma once + +#include "cbinds/Generator.h" +#include "metawear/platform/dllmarker.h" + +class JavaScriptGenerator : public mbientlab::cbinds::Generator { +public: + virtual ~JavaScriptGenerator(); + + virtual void create(std::ostream& os, const mbientlab::cbinds::CHeaderFile& header); +}; + +extern "C" METAWEAR_API mbientlab::cbinds::Generator* createJavaScriptGenerator(); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/PythonGenerator.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/PythonGenerator.cpp new file mode 100644 index 0000000..8635f1b --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/PythonGenerator.cpp @@ -0,0 +1,341 @@ +#include "PythonGenerator.h" +#include "cbinds/Util.h" +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include + +using std::endl; +using std::function; +using std::isdigit; +using std::isupper; +using std::ostream; +using std::string; +using std::stringstream; +using std::toupper; +using std::unordered_map; +using std::unordered_set; + +using namespace mbientlab::cbinds; + +static const unordered_map FN_TYPE_NAME_MAPPING = { + { "float" , "Float" }, + { "void" , "Void" }, + { "int64_t" , "Long" }, + { "int32_t" , "Int" }, + { "int8_t" , "Byte" }, + { "uint8_t" , "UByte" }, + { "uint16_t" , "UShort" }, + { "uint32_t" , "UInt" }, + { "uint64_t" , "Ulong" } +}; + +Generator* createPythonGenerator() { + return new PythonGenerator(); +} + +PythonGenerator::~PythonGenerator() { + +} + +void PythonGenerator::create(ostream& os, const CHeaderFile& header) { + unordered_map typeMapping = { + { "float" , "c_float" }, + { "void" , "None" }, + { "int64_t" , "c_longlong" }, + { "int32_t" , "c_int" }, + { "int8_t" , "c_byte" }, + { "uint8_t" , "c_ubyte" }, + { "uint16_t" , "c_ushort" }, + { "uint32_t" , "c_uint" }, + { "uint64_t" , "c_ulonglong" } + }; + + os << "# Warning!!!" << endl + << "# This python module is generated from the MetaWear C++ API header files" << endl + << "# Do not edit" << endl + << "from ctypes import * " << endl + << "import sys" << endl + << "import copy" << endl + << endl; + + os << "if sys.version_info[0] == 2:" << endl + << " range = xrange" << endl << endl + << "def array_ubyte_eq(a, a_len, b, b_len):" << endl + << " if (a_len != b_len):" << endl + << " return False" << endl + << " for i in range(a_len):" << endl + << " if (a[i] != b[i]):" << endl + << " return False" << endl + << " return True" << endl + << endl; + + os << "def array_ubyte_to_hex_string(a, a_len):" << endl + << " if (a_len == 0):" << endl + << " return \"[]\"" << endl + << " string = \"[\" + \"0x%02x\" % (a[0])" << endl + << " for i in range(a_len - 1):" << endl + << " string+= \", \" + \"0x%02x\" % (a[i + 1])" << endl + << " string+= \"]\"" << endl + << " return string" << endl + << endl; + + os << "def array_ubyte_deep_copy(a, a_len):" << endl + << " ptr = cast(a, POINTER(c_ubyte * a_len))" << endl + << " return cast(copy.deepcopy(ptr.contents), POINTER(c_ubyte))" << endl + << endl; + + os << "def module_info_eq(this, that):" << endl + << " return (this.name == that.name and array_ubyte_eq(this.extra, this.extra_len, that.extra, that.extra_len) and this.present == that.present and this.implementation == that.implementation and this.revision == that.revision)" << endl + << endl; + + os << "def module_info_repr(this):" << endl + << " return \"{name : %s, extra : %s, extra_len : %d, present : %d, implementation : %d, revision : %d}\" % (this.name, array_ubyte_to_hex_string(this.extra, this.extra_len), this.extra_len, this.present, this.implementation, this.revision)" << endl + << endl; + + os << "def module_info_deepcopy(this, memo):" << endl + << " return ModuleInfo(name = this.name, extra = array_ubyte_deep_copy(this.extra, this.extra_len), extra_len = this.extra_len, present = this.present, implementation = this.implementation, revision = this.revision)" << endl + <getEntries()) { + string stripped = strip(entry.name, prefix); + if (stripped == entry.name) { + stripped = strip(entry.name, SHORTENED_PREFIXES.at(it.first)); + } + if (isdigit(stripped[0])) { + stripped = "_" + stripped; + } + os << " " << stripped << " = " << entry.value << endl; + } + os << endl; + } + + unordered_set fnPtrs, structs, presetTypeNames; + auto convertFnTypeName = [&](const Type& type) -> string { + if (header.getStructs().count(type.getName()) && header.getStructs().at(type.getName())->isForwardDecl() && type.isPointer()) { + return "VoidP"; + } + + string stripped(strip(type.getName(), "MblMw")); + string name= FN_TYPE_NAME_MAPPING.count(stripped) ? FN_TYPE_NAME_MAPPING.at(stripped) : stripped; + if (type.isPointer()) { + name+= "P"; + } + return name; + }; + auto convertType = [&](const Type& type) -> string { + auto arraySize = type.getArraySize(); + if (type.isArray() && arraySize != -1) { + // only need array of native types for now + // will need to expand this if we do array of objects or pointers + stringstream result; + result << "(" << typeMapping.at(type.getName()) << " * " << arraySize << ")"; + return result.str(); + } else if (type.isPointer() || (type.isArray() && arraySize == -1)) { + auto isFnPtr = dynamic_cast(&type) != nullptr; + if (header.getStructs().count(type.getName())) { + auto structObj = header.getStructs().at(type.getName()); + if (header.getStructs().at(type.getName())->isForwardDecl()) { + return "c_void_p"; + } else { + return "POINTER(" + typeMapping.at(structObj->getName()) + ")"; + } + } else if (type.getName() == "char") { + return "c_char_p"; + } else if (typeMapping.count(type.getName()) && !isFnPtr) { + return type.getName() == "void" ? "c_void_p" : "POINTER(" + typeMapping.at(type.getName()) + ")"; + } else if (isFnPtr) { + return typeMapping.at(type.getName()); + } + return "c_void_p"; + } else { + return typeMapping.at(type.getName()); + } + }; + function printStruct; + function printFunctionPtr = [&](const FunctionPointer* fnPointer) -> void { + if (fnPtrs.count(fnPointer->getName())) { + return; + } + + string mappedName("Fn" + convertFnTypeName(*(fnPointer->getReturnType()))); + for(auto& param: fnPointer->getParameters()) { + auto& type = param->getType(); + + if (header.getStructs().count(type.getName())) { + printStruct(header.getStructs().at(type.getName())); + } + + mappedName+= "_" + convertFnTypeName(type); + } + + typeMapping.insert({fnPointer->getName(), mappedName}); + if (presetTypeNames.count(mappedName)) { + return; + } + presetTypeNames.insert(mappedName); + + os << mappedName << " = CFUNCTYPE("; + os << convertType(*fnPointer->getReturnType()); + for(auto& param: fnPointer->getParameters()) { + os << ", " << convertType(param->getType()); + } + os << ")" << endl; + fnPtrs.insert(fnPointer->getName()); + }; + printStruct = [&](const Struct* structObj) -> void { + if (structs.count(structObj->getName())) { + return; + } + + if (structObj->isForwardDecl()) { + typeMapping.insert({structObj->getName(), "c_void_p"}); + } else { + for(auto& field: structObj->getFields()) { + const FunctionPointer* fnPtr; + if ((fnPtr = dynamic_cast(&field->getType())) != nullptr) { + printFunctionPtr(fnPtr); + } + } + + string strippedName(strip(structObj->getName(), "MblMw")); + typeMapping.insert({structObj->getName(), strippedName}); + + bool first = true; + string eqLine, strFormat, strElem, deepcopyLine; + os << "class " << strippedName << "(Structure):" << endl + << " _fields_ = [" << endl; + for(auto field: structObj->getFields()) { + if (!first) { + os << "," << endl; + strFormat+= ", "; + strElem+= ", "; + eqLine+= " and "; + deepcopyLine+= ", "; + } + os << " (\"" << field->getName() << "\" , " << convertType(field->getType()) << ")"; + + strFormat+= field->getName() + " : "; + auto fieldType = field->getType().getName(); + if (fieldType == "float") { + strFormat+= "%.3f"; + eqLine+= "is_close(self." + field->getName() + ", other." + field->getName() + ")"; + strElem+= "self." + field->getName(); + } else if (fieldType == "char" && field->getType().isPointer()) { + strFormat+= "%s"; + eqLine+= "self." + field->getName() + " == " + "other." + field->getName(); + strElem+= "self." + field->getName(); + } else if (field->getType().isArray() && field->getType().getArraySize() != -1) { + strFormat+= "%s"; + { + stringstream buffer; + buffer << "array_ubyte_eq(self." << field->getName() << ", " << field->getType().getArraySize() + << ", other." << field->getName() << ", " << field->getType().getArraySize() << ")"; + eqLine+= buffer.str(); + } + { + stringstream buffer; + buffer << "array_ubyte_to_hex_string(self." << field->getName() << ", " << field->getType().getArraySize() << ")"; + strElem+= buffer.str(); + } + } else { + strFormat+= "%d"; + eqLine+= "self." + field->getName() + " == " + "other." + field->getName(); + strElem+= "self." + field->getName(); + } + + if (field->getType().isArray() && field->getType().getArraySize() != -1) { + deepcopyLine+= field->getName() + " = copy.deepcopy(self." + field->getName() + ")"; + } else { + deepcopyLine+= field->getName() + " = self." + field->getName(); + } + + first = false; + } + os << endl << " ]" << endl << endl; + + os << " def __neq__(self, other):" << endl + << " return not self.__eq__(other)" << endl << endl; + + if (structObj->getName() == "MblMwModuleInfo") { + os << " def __eq__(self, other):" << endl + << " return module_info_eq(self, other)" << endl << endl; + + os << " def __repr__(self):" << endl + << " return module_info_repr(self)" << endl << endl; + + os << " def __deepcopy__(self, memo):" << endl + << " return module_info_deepcopy(self, memo)" << endl << endl; + } else { + os << " def __eq__(self, other):" << endl + << " return (" << eqLine << ")" << endl << endl; + + os << " def __repr__(self):" << endl + << " return \"{" << strFormat << "}\" % (" << strElem << ")" << endl << endl; + + os << " def __deepcopy__(self, memo):" << endl + << " return " << strippedName << "(" << deepcopyLine << ")" << endl << endl; + } + } + structs.insert(structObj->getName()); + }; + + for(auto it: header.getFunctionPointers()) { + printFunctionPtr(it.second); + } + + for(auto it: header.getStructs()) { + printStruct(it.second); + } + + os << "class Const:" << endl; + for(auto it: header.getConstants()) { + if (header.getStructs().count(it.second->getType()->getName())) { + auto structObj = header.getStructs().at(it.second->getType()->getName()); + os << " " << strip(it.second->getName(), "MBL_MW_") << " = " << typeMapping.at(it.second->getType()->getName()) << "("; + + bool first = true; + for(size_t i = 0 ; i < structObj->getFields().size(); i++) { + if (!first) { + os << ", "; + } + os << structObj->getFields()[i]->getName() << " = " << it.second->getValueComponents()[i]; + first = false; + } + os << ")" << endl; + } else { + os << " " << strip(it.second->getName(), "MBL_MW_") << " = " << it.second->getValue() << endl; + } + } + os << endl; + + os << "def init_libmetawear(libmetawear):" << endl; + for(auto it: header.getFunctions()) { + os << " libmetawear." << it.first << ".restype = " << convertType(*(it.second->getReturnType())) << endl; + + os << " libmetawear." << it.first << ".argtypes = ["; + bool first = true; + for(auto param: it.second->getParameters()) { + if (!first) { + os << ", "; + } + os << convertType(param->getType()); + first = false; + } + + os << "]" << endl << endl; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/PythonGenerator.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/PythonGenerator.h new file mode 100644 index 0000000..54edea4 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/PythonGenerator.h @@ -0,0 +1,13 @@ +#pragma once + +#include "cbinds/Generator.h" +#include "metawear/platform/dllmarker.h" + +class PythonGenerator : public mbientlab::cbinds::Generator { +public: + virtual ~PythonGenerator(); + + virtual void create(std::ostream& os, const mbientlab::cbinds::CHeaderFile& header); +}; + +extern "C" METAWEAR_API mbientlab::cbinds::Generator* createPythonGenerator(); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/SwiftGenerator.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/SwiftGenerator.cpp new file mode 100644 index 0000000..28ef35c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/SwiftGenerator.cpp @@ -0,0 +1,40 @@ +#include "SwiftGenerator.h" +#include "cbinds/Util.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using std::endl; +using std::function; +using std::isdigit; +using std::isupper; +using std::ostream; +using std::string; +using std::stringstream; +using std::toupper; +using std::unordered_map; +using std::unordered_set; + +using namespace mbientlab::cbinds; + +Generator* createSwiftGenerator() { + return new SwiftGenerator(); +} + +SwiftGenerator::~SwiftGenerator() { + +} + +void SwiftGenerator::create(ostream& os, const CHeaderFile& header) { + for(auto it: header.getConstants()) { + if (!header.getStructs().count(it.second->getType()->getName())) { + os << "public let " << strip(it.second->getName(), "MBL_MW_") << " = " << it.second->getValue() << endl; + } + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/SwiftGenerator.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/SwiftGenerator.h new file mode 100644 index 0000000..83db1a2 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/SwiftGenerator.h @@ -0,0 +1,13 @@ +#pragma once + +#include "cbinds/Generator.h" +#include "metawear/platform/dllmarker.h" + +class SwiftGenerator : public mbientlab::cbinds::Generator { +public: + virtual ~SwiftGenerator(); + + virtual void create(std::ostream& os, const mbientlab::cbinds::CHeaderFile& header); +}; + +extern "C" METAWEAR_API mbientlab::cbinds::Generator* createSwiftGenerator(); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/common.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/common.cpp new file mode 100644 index 0000000..3b1d2cb --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/common.cpp @@ -0,0 +1,36 @@ +#include "common.h" + +using std::string; +using std::unordered_map; + +unordered_map SHORTENED_PREFIXES = { + { "MblMwComparatorOperation", "MBL_MW_COMPARATOR_OP_" }, + { "MblMwNeoPixelColorOrdering", "MBL_MW_NP_" }, + { "MblMwNeoPixelRotDirection", "MBL_MW_NP_ROT_DIR_" }, + { "MblMwDataTypeId", "MBL_MW_DT_ID_" }, + { "MblMwMetaWearRProChannel", "MBL_MW_METAWEAR_RPRO_CHANNEL_" }, + { "MblMwMathOperation", "MBL_MW_MATH_OP_"}, + { "MblMwAlsLtr329IntegrationTime", "MBL_MW_ALS_LTR329_TIME_" }, + { "MblMwAlsLtr329MeasurementRate", "MBL_MW_ALS_LTR329_RATE_" }, + { "MblMwTimeMode", "MBL_MW_TIME_" }, + { "MblMwColorDetectorTcs34725Gain", "MBL_MW_CD_TCS34725_GAIN_" }, + { "MblMwGattCharWriteType", "MBL_MW_GATT_CHAR_WRITE_" }, + { "MblMwWhitelistFilter", "MBL_MW_WHITELIST_FILTER_"}, + { "MblMwAccBoschDoubleTapWindow", "MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_"} +}; + +string createPrefix(const string& in) { + string prefix; + bool first = true; + + for(auto ch: in) { + if (!first && isupper(ch) && ch != 'W') { + prefix+= "_"; + } + prefix+= toupper(ch); + first = false; + } + prefix+= "_"; + + return prefix; +} \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/common.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/common.h new file mode 100644 index 0000000..495a898 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/generator/cpp/common.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +extern std::unordered_map SHORTENED_PREFIXES; + +std::string createPrefix(const std::string& in); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/datainterpreter.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/datainterpreter.cpp new file mode 100644 index 0000000..a736294 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/datainterpreter.cpp @@ -0,0 +1,496 @@ +#include +#include +#include +#include +#include + +#include "metawear/core/types.h" +#include "metawear/core/settings.h" +#include "metawear/core/cpp/datainterpreter.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/sensor/accelerometer_bosch.h" +#include "metawear/sensor/cpp/accelerometer_bosch_private.h" +#include "metawear/sensor/cpp/gyro_bosch_private.h" +#include "metawear/core/cpp/logging_private.h" +#include "metawear/processor/cpp/dataprocessor_config.h" +#include "metawear/processor/cpp/dataprocessor_private.h" + +using namespace std; +using namespace std::chrono; + +struct CartesianShort { + int16_t x, y, z; +}; + +#define CAST_INT32(x) uint8_t max_pos= log_data ? min(len, signal->length()) : min(len, (uint8_t) (signal->offset + signal->length()));\ + x= (response[max_pos - 1] & 0x80) == 0x80 ? -1 : 0;\ + if (log_data) {\ + memcpy(&x, response, max_pos);\ + } else {\ + memcpy(&x, response + signal->offset, max_pos - signal->offset);\ + } + +#define CAST_UINT32(x) if (log_data) {\ + memcpy(&x, response, sizeof(uint32_t));\ + } else {\ + uint8_t max_pos= min(len, (uint8_t) (signal->offset + signal->length()));\ + memcpy(&x, response + signal->offset, max_pos - signal->offset);\ + } + +#define CREATE_MESSAGE(dt_id) MblMwData *msg= (MblMwData*) malloc(sizeof(MblMwData));\ + msg->value= value;\ + msg->type_id= dt_id;\ + msg->length= sizeof(*value);\ + return msg + +#define CONVERT_TO_FLOAT(name, raw_type, scale) static MblMwData* name(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) {\ + raw_type unscaled;\ + CAST_INT32(unscaled)\ +\ + float *value= (float*) malloc(sizeof(float));\ + *value= unscaled / scale;\ +\ + CREATE_MESSAGE(MBL_MW_DT_ID_FLOAT);\ +}\ + +#define RAW_CONVERT(name, type, type_id) static MblMwData* name(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) {\ + type* value = (type*) malloc(sizeof(type));\ + memcpy(value, response, sizeof(type));\ + CREATE_MESSAGE(type_id);\ +}\ + +const float BOSCH_BARO_SCALE= 256.f, TEMPERATURE_SCALE= 8.f, MMA8452Q_ACC_SCALE= 1000.f, BMM150_SCALE= 16.f, BME280_HUMIDITY_SCALE= 1024.f, + Q16_16_SCALE= 0x10000, SENSOR_FUSION_ACC_SCALE = 1000.f, MSS_TO_G_SCALE = 9.80665f; + +static MblMwData* convert_to_int32(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + int32_t *value = (int32_t*) malloc(sizeof(int32_t)); + + CAST_INT32(*value) + CREATE_MESSAGE(MBL_MW_DT_ID_INT32); +} + +static MblMwData* convert_to_uint32(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + uint32_t *value= (uint32_t*) calloc(1, sizeof(uint32_t)); + + CAST_UINT32(*value); + CREATE_MESSAGE(MBL_MW_DT_ID_UINT32); +} + +static MblMwData* convert_to_mma8452q_acceleration(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + CartesianShort milliG; + memcpy(&milliG, response, sizeof(milliG)); + + MblMwCartesianFloat *value= (MblMwCartesianFloat*) malloc(sizeof(MblMwCartesianFloat)); + value->x= milliG.x / MMA8452Q_ACC_SCALE; + value->y= milliG.y / MMA8452Q_ACC_SCALE; + value->z= milliG.z / MMA8452Q_ACC_SCALE; + + CREATE_MESSAGE(MBL_MW_DT_ID_CARTESIAN_FLOAT); +} + +static MblMwData* convert_to_bosch_acceleration(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + CartesianShort unscaled; + memcpy(&unscaled, response, sizeof(unscaled)); + + float scale = bosch_get_data_scale(signal->owner); + + MblMwCartesianFloat *value = (MblMwCartesianFloat*)malloc(sizeof(MblMwCartesianFloat)); + value->x = unscaled.x / scale; + value->y = unscaled.y / scale; + value->z = unscaled.z / scale; + + CREATE_MESSAGE(MBL_MW_DT_ID_CARTESIAN_FLOAT); +} + +static MblMwData* convert_to_bosch_acceleration_single_axis(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + int32_t unscaled; + CAST_INT32(unscaled) + + float *value = (float*) malloc(sizeof(float)); + *value = unscaled / bosch_get_data_scale(signal->owner); + + CREATE_MESSAGE(MBL_MW_DT_ID_FLOAT); +} + +static MblMwData* convert_to_bosch_acceleration_unsigned_single_axis(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + uint32_t unscaled= 0; + CAST_UINT32(unscaled) + + float *value= (float*) malloc(sizeof(float)); + *value = unscaled / bosch_get_data_scale(signal->owner); + + CREATE_MESSAGE(MBL_MW_DT_ID_FLOAT); +} + +static MblMwData* convert_to_bosch_rotation(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + CartesianShort unscaled; + memcpy(&unscaled, response, sizeof(unscaled)); + + float scale = bosch_gyro_get_data_scale(signal->owner); + + MblMwCartesianFloat *value = (MblMwCartesianFloat*)malloc(sizeof(MblMwCartesianFloat)); + value->x = unscaled.x / scale; + value->y = unscaled.y / scale; + value->z = unscaled.z / scale; + + CREATE_MESSAGE(MBL_MW_DT_ID_CARTESIAN_FLOAT); +} + +static MblMwData* convert_to_bosch_rotation_single_axis(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + int32_t unscaled; + CAST_INT32(unscaled) + + float *value = (float*) malloc(sizeof(float)); + *value = unscaled / bosch_gyro_get_data_scale(signal->owner); + + CREATE_MESSAGE(MBL_MW_DT_ID_FLOAT); +} + +static MblMwData* convert_to_bosch_rotation_unsigned_single_axis(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + uint32_t unscaled= 0; + CAST_UINT32(unscaled) + + float *value= (float*) malloc(sizeof(float)); + *value = unscaled / bosch_gyro_get_data_scale(signal->owner); + + CREATE_MESSAGE(MBL_MW_DT_ID_FLOAT); +} + +static MblMwData* convert_to_byte_array(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwData *msg= (MblMwData*) malloc(sizeof(MblMwData)); + msg->type_id= MBL_MW_DT_ID_BYTE_ARRAY; + msg->length= len; + + msg->value= malloc(len); + memcpy(msg->value, response, len); + + return msg; +} + +static MblMwData* convert_to_bmm150_b_field(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + CartesianShort unscaled; + memcpy(&unscaled, response, sizeof(unscaled)); + + MblMwCartesianFloat *value = (MblMwCartesianFloat*)malloc(sizeof(MblMwCartesianFloat)); + value->x = unscaled.x / BMM150_SCALE; + value->y = unscaled.y / BMM150_SCALE; + value->z = unscaled.z / BMM150_SCALE; + + CREATE_MESSAGE(MBL_MW_DT_ID_CARTESIAN_FLOAT); +} + +static MblMwData* convert_to_battery_state(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwBatteryState *value= (MblMwBatteryState*) malloc(sizeof(MblMwBatteryState)); + memcpy(&value->voltage, response + 1, 2); + value->charge= response[0]; + + CREATE_MESSAGE(MBL_MW_DT_ID_BATTERY_STATE); +} + +static MblMwData* convert_to_bosch_any_motion(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwBoschAnyMotion *value= (MblMwBoschAnyMotion*) malloc(sizeof(MblMwBoschAnyMotion)); + auto detected = [response](uint8_t& field, uint8_t axis) { + auto mask = 0x1 << (axis + 3); + field = (mask & response[0]) == mask; + }; + + value->sign = (response[0] & 0x40) != 0x40; + detected(value->x_axis_active, 0); + detected(value->y_axis_active, 1); + detected(value->z_axis_active, 2); + + CREATE_MESSAGE(MBL_MW_DT_ID_BOSCH_ANY_MOTION); +} + +static MblMwData* convert_to_bmi270_gesture(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwBoschGestureType *value= (MblMwBoschGestureType*) malloc(sizeof(MblMwBoschGestureType)); + + value->type = response[0] & 0x03; + + uint32_t temp = response[0]; + temp = temp >> 2; + value->gesture_code = temp; + + CREATE_MESSAGE(MBL_MW_DT_ID_BOSCH_GESTURE); +} + +static MblMwData* convert_to_bmi270_activity(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + uint32_t temp = response[0]; + temp = temp >> 1; + + uint32_t *value= (uint32_t*) calloc(1, sizeof(uint32_t)); + memcpy(value, &temp, sizeof(uint32_t)); + + CREATE_MESSAGE(MBL_MW_DT_ID_UINT32); +} + +CONVERT_TO_FLOAT(convert_to_temperature, int32_t, TEMPERATURE_SCALE) + +CONVERT_TO_FLOAT(convert_to_mma8452q_acceleration_single_axis, int32_t, MMA8452Q_ACC_SCALE) +CONVERT_TO_FLOAT(convert_to_mma8452q_acceleration_unsigned_single_axis, uint32_t, MMA8452Q_ACC_SCALE) + +CONVERT_TO_FLOAT(convert_to_bmp280_pressure, uint32_t, BOSCH_BARO_SCALE) +CONVERT_TO_FLOAT(convert_to_bmp280_altitude, int32_t, BOSCH_BARO_SCALE) + +CONVERT_TO_FLOAT(convert_to_bmm150_b_field_single_axis, int32_t, BMM150_SCALE) +CONVERT_TO_FLOAT(convert_to_bmm150_b_field_unsigned_single_axis, uint32_t, BMM150_SCALE) + +CONVERT_TO_FLOAT(convert_to_bme280_humidity, uint32_t, BME280_HUMIDITY_SCALE) +CONVERT_TO_FLOAT(convert_to_q16_16_fixed_point, int32_t, Q16_16_SCALE) + +RAW_CONVERT(convert_to_tcs34725_adc, MblMwTcs34725ColorAdc, MBL_MW_DT_ID_TCS34725_ADC) +RAW_CONVERT(convert_to_quaternion, MblMwQuaternion, MBL_MW_DT_ID_QUATERNION) +RAW_CONVERT(convert_to_euler_angles, MblMwEulerAngles, MBL_MW_DT_ID_EULER_ANGLE) +RAW_CONVERT(convert_to_corrected_vector3, MblMwCorrectedCartesianFloat, MBL_MW_DT_ID_CORRECTED_CARTESIAN_FLOAT) + +static MblMwData* convert_to_vector3(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwCartesianFloat unscaled, *value = (MblMwCartesianFloat*) malloc(sizeof(MblMwCartesianFloat)); + memcpy(&unscaled, response, sizeof(MblMwCartesianFloat)); + + value->x = unscaled.x / MSS_TO_G_SCALE; + value->y = unscaled.y / MSS_TO_G_SCALE; + value->z = unscaled.z / MSS_TO_G_SCALE; + + CREATE_MESSAGE(MBL_MW_DT_ID_CARTESIAN_FLOAT); +} + +static MblMwData* convert_to_corrected_acc(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwCorrectedCartesianFloat unscaled, *value = (MblMwCorrectedCartesianFloat*) malloc(sizeof(MblMwCorrectedCartesianFloat)); + memcpy(&unscaled, response, sizeof(float) * 3); + + value->x = unscaled.x / SENSOR_FUSION_ACC_SCALE; + value->y = unscaled.y / SENSOR_FUSION_ACC_SCALE; + value->z = unscaled.z / SENSOR_FUSION_ACC_SCALE; + value->accuracy = response[12]; + + CREATE_MESSAGE(MBL_MW_DT_ID_CORRECTED_CARTESIAN_FLOAT); +} + +static MblMwData* convert_to_overflow_state(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwOverflowState *value= (MblMwOverflowState*) malloc(sizeof(MblMwOverflowState)); + memcpy(&value->length, response + 1, 2); + value->assert_en= response[0]; + + CREATE_MESSAGE(MBL_MW_DT_ID_OVERFLOW_STATE); +} + +static MblMwData* convert_to_sensor_orientation(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwSensorOrientation *value= (MblMwSensorOrientation*) malloc(sizeof(MblMwSensorOrientation)); + *value = (MblMwSensorOrientation) (((response[0] & 0x6) >> 1) + 4 * ((response[0] & 0x8) >> 3)); + + CREATE_MESSAGE(MBL_MW_DT_ID_SENSOR_ORIENTATION); +} + +static MblMwData* convert_to_mac_address(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + const int strSize = 17 + 1; + const uint8_t offset = len == 7 ? 1 : 0; + char *value = (char *)malloc(strSize); + sprintf(value, "%02X:%02X:%02X:%02X:%02X:%02X", response[5 + offset], response[4 + offset], + response[3 + offset], response[2 + offset], response[1 + offset], response[0 + offset]); + value[strSize - 1] = '\0'; + + MblMwData *msg = (MblMwData*)malloc(sizeof(MblMwData)); + msg->value = value; + msg->type_id = MBL_MW_DT_ID_STRING; + msg->length = strSize; + return msg; +} + +static MblMwData* convert_to_sensor_orientation_mma8452q(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwSensorOrientation *value= (MblMwSensorOrientation*) malloc(sizeof(MblMwSensorOrientation)); + uint32_t offset = (response[0] & 0x06) >> 1; + *value = (MblMwSensorOrientation) (4 * (response[0] & 0x01) + ((offset == 2 || offset == 3) ? offset ^ 0x1 : offset)); + + CREATE_MESSAGE(MBL_MW_DT_ID_SENSOR_ORIENTATION); +} + +static MblMwData* convert_to_logging_time(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwLoggingTime *value = (MblMwLoggingTime*)malloc(sizeof(MblMwLoggingTime)); + + // We need to convert the local MetaWear time in 'real' Earth time + value->epoch = duration_cast(system_clock::now().time_since_epoch()).count(); + // Get the current reading of the MetaWear clock + uint32_t tick; + memcpy(&tick, response, 4); + // By going backwards the number of miliseconds the current MetaWear time + // represents, we find the real world time the MetaWear booted + value->epoch -= static_cast(round((double)tick * TICK_TIME_STEP)); + // Each MetaWear reset event has a corresponding reset_uid + value->reset_uid = response[4]; + + CREATE_MESSAGE(MBL_MW_DT_ID_LOGGING_TIME); +} + +static MblMwData* convert_to_btle_address(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwBtleAddress *value = (MblMwBtleAddress*)malloc(sizeof(MblMwBtleAddress)); + memcpy(value, response, sizeof(MblMwBtleAddress)); + + CREATE_MESSAGE(MBL_MW_DT_ID_BTLE_ADDRESS); +} + +static MblMwData* convert_to_calibration_state(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwCalibrationState *value = (MblMwCalibrationState*)malloc(sizeof(MblMwCalibrationState)); + memcpy(value, response, sizeof(MblMwCalibrationState)); + + CREATE_MESSAGE(MBL_MW_DT_ID_CALIBRATION_STATE); +} + +static MblMwData* convert_to_fused(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + auto processor = dynamic_cast(signal); + if (processor->type != DataProcessorType::FUSER) { + return convert_to_fused(log_data, processor->input, response, len); + } + + auto fused_config = (FuseConfig*) processor->config; + MblMwData** value = (MblMwData**) calloc(fused_config->count + 1, sizeof(MblMwData*)); + uint8_t offset = 0; + MblMwData* partialMsg; + + partialMsg = data_response_converters.at(processor->input->interpreter)(log_data, signal, response, len); + value[0] = partialMsg; + offset+= processor->input->length(); + + for(uint8_t i = 0; i < fused_config->count; i++, offset+= processor->length()) { + processor = lookup_processor(signal->owner, fused_config->references[i]); + partialMsg = data_response_converters.at(processor->interpreter)(log_data, processor, response + offset, len - offset); + value[i + 1] = partialMsg; + } + + MblMwData *msg= (MblMwData*) malloc(sizeof(MblMwData)); + msg->value= value; + msg->type_id= MBL_MW_DT_ID_DATA_ARRAY; + msg->length= sizeof(MblMwData*) * (fused_config->count + 1); + + return msg; +} + +static MblMwData* convert_to_bosch_tap(bool log_data, const MblMwDataSignal* signal, const uint8_t *response, uint8_t len) { + MblMwBoschTap *value = (MblMwBoschTap*) malloc(sizeof(MblMwBoschTap)); + + if ((response[0] & 0x1) == 0x1) { + value->type = 0x1; + } else if ((response[0] & 0x2) == 0x2) { + value->type = 0x2; + } else { + value->type = 0; + } + value->sign = (response[0] & 0x20) == 0x20; + + CREATE_MESSAGE(MBL_MW_DT_ID_BOSCH_TAP); +} + +unordered_map data_response_converters = { + { DataInterpreter::INT32 , convert_to_int32 }, + { DataInterpreter::UINT32 , convert_to_uint32 }, + { DataInterpreter::TEMPERATURE , convert_to_temperature }, + { DataInterpreter::BOSCH_PRESSURE , convert_to_bmp280_pressure }, + { DataInterpreter::BOSCH_ALTITUDE , convert_to_bmp280_altitude }, + { DataInterpreter::BOSCH_ROTATION , convert_to_bosch_rotation }, + { DataInterpreter::BOSCH_ROTATION_SINGLE_AXIS , convert_to_bosch_rotation_single_axis }, + { DataInterpreter::BOSCH_ROTATION_UNSIGNED_SINGLE_AXIS , convert_to_bosch_rotation_unsigned_single_axis }, + { DataInterpreter::BOSCH_ACCELERATION , convert_to_bosch_acceleration }, + { DataInterpreter::BOSCH_ACCELERATION_SINGLE_AXIS , convert_to_bosch_acceleration_single_axis }, + { DataInterpreter::BOSCH_ACCELERATION_UNSIGNED_SINGLE_AXIS , convert_to_bosch_acceleration_unsigned_single_axis }, + { DataInterpreter::MMA8452Q_ACCELERATION , convert_to_mma8452q_acceleration }, + { DataInterpreter::MMA8452Q_ACCELERATION_SINGLE_AXIS , convert_to_mma8452q_acceleration_single_axis }, + { DataInterpreter::MMA8452Q_ACCELERATION_UNSIGNED_SINGLE_AXIS , convert_to_mma8452q_acceleration_unsigned_single_axis }, + { DataInterpreter::BYTE_ARRAY , convert_to_byte_array }, + { DataInterpreter::BMM150_B_FIELD , convert_to_bmm150_b_field }, + { DataInterpreter::BMM150_B_FIELD_SINGLE_AXIS , convert_to_bmm150_b_field_single_axis }, + { DataInterpreter::BMM150_B_FIELD_UNSIGNED_SINGLE_AXIS , convert_to_bmm150_b_field_unsigned_single_axis }, + { DataInterpreter::SETTINGS_BATTERY_STATE , convert_to_battery_state }, + { DataInterpreter::TCS34725_COLOR_ADC , convert_to_tcs34725_adc }, + { DataInterpreter::BME280_HUMIDITY , convert_to_bme280_humidity }, + { DataInterpreter::Q16_16_FIXED_POINT , convert_to_q16_16_fixed_point }, + { DataInterpreter::SENSOR_FUSION_QUATERNION , convert_to_quaternion }, + { DataInterpreter::SENSOR_FUSION_EULER_ANGLE , convert_to_euler_angles }, + { DataInterpreter::SENSOR_FUSION_CORRECTED_FLOAT_VECTOR3 , convert_to_corrected_vector3 }, + { DataInterpreter::SENSOR_FUSION_FLOAT_VECTOR3 , convert_to_vector3 }, + { DataInterpreter::SENSOR_FUSION_CORRECTED_ACC , convert_to_corrected_acc }, + { DataInterpreter::DEBUG_OVERFLOW_STATE , convert_to_overflow_state }, + { DataInterpreter::SENSOR_ORIENTATION, convert_to_sensor_orientation }, + { DataInterpreter::MAC_ADDRESS, convert_to_mac_address }, + { DataInterpreter::SENSOR_ORIENTATION_MMA8452Q, convert_to_sensor_orientation_mma8452q }, + { DataInterpreter::LOGGING_TIME, convert_to_logging_time }, + { DataInterpreter::BTLE_ADDRESS, convert_to_btle_address }, + { DataInterpreter::BOSCH_ANY_MOTION, convert_to_bosch_any_motion }, + { DataInterpreter::SENSOR_FUSION_CALIB_STATE, convert_to_calibration_state }, + { DataInterpreter::FUSED_DATA, convert_to_fused }, + { DataInterpreter::BOSCH_TAP, convert_to_bosch_tap }, + { DataInterpreter::BMI270_GESTURE , convert_to_bmi270_gesture }, + { DataInterpreter::BMI270_ACTIVITY , convert_to_bmi270_activity } +}; + +static float bosch_acc_to_firmware(const MblMwDataSignal* signal, float value) { + return value * bosch_get_data_scale(signal->owner); +} + +static float mma8452q_to_firmware(const MblMwDataSignal* signal, float value) { + return value * MMA8452Q_ACC_SCALE; +} + +static float bosch_baro_to_firmware(const MblMwDataSignal* signal, float value) { + return value * BOSCH_BARO_SCALE; +} + +static float bosch_gyro_to_firmware(const MblMwDataSignal* signal, float value) { + return value * bosch_gyro_get_data_scale(signal->owner); +} + +static float number_to_firmware_default(const MblMwDataSignal* signal, float value) { + return value; +} + +static float bme280_humidity_to_firmware(const MblMwDataSignal* signal, float value) { + return value * BME280_HUMIDITY_SCALE; +} + +static float temp_to_firmware(const MblMwDataSignal* signal, float value) { + return value * TEMPERATURE_SCALE; +} + +static float q16_16_fixed_point_to_firmware(const MblMwDataSignal* signal, float value) { + return value * Q16_16_SCALE; +} + +static float bosch_magnetometer_to_firmware(const MblMwDataSignal* signal, float value) { + return value * BMM150_SCALE; +} + +unordered_map number_to_firmware_converters = { + { FirmwareConverter::DEFAULT , number_to_firmware_default }, + { FirmwareConverter::BME280_HUMIDITY , bme280_humidity_to_firmware }, + { FirmwareConverter::BOSCH_ACCELERATION , bosch_acc_to_firmware }, + { FirmwareConverter::BOSCH_BAROMETER , bosch_baro_to_firmware }, + { FirmwareConverter::BOSCH_ROTATION , bosch_gyro_to_firmware }, + { FirmwareConverter::MMA8452Q_ACCELERATION , mma8452q_to_firmware}, + { FirmwareConverter::TEMPERATURE , temp_to_firmware}, + { FirmwareConverter::Q16_16_FIXED_POINT , q16_16_fixed_point_to_firmware}, + { FirmwareConverter::BOSCH_MAGNETOMETER , bosch_magnetometer_to_firmware}, +}; + +namespace std { + +size_t hash::operator()(const DataInterpreter& key) const { + return static_cast(key); +} + +size_t hash::operator()(const FirmwareConverter& key) const { + return static_cast(key); +} + +} + +void free_data(const MblMwDataSignal* signal, MblMwData* data) { + if (data->type_id == MBL_MW_DT_ID_DATA_ARRAY) { + auto processor = dynamic_cast(signal); + auto fused_config = (FuseConfig*) processor->config; + auto casted = (MblMwData**) data->value; + + for(uint8_t i = 0; i < fused_config->count; i++) { + free(casted[i]); + } + } + free(data->value); + free(data); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/metawearboard.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/metawearboard.cpp new file mode 100644 index 0000000..308de50 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/metawearboard.cpp @@ -0,0 +1,896 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "metawear/core/metawearboard.h" +#include "metawear/core/status.h" +#include "metawear/core/logging.h" +#include "metawear/core/datasignal.h" +#include "metawear/core/types.h" + +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/debug_private.h" +#include "metawear/core/cpp/event_register.h" +#include "metawear/core/cpp/logging_register.h" +#include "metawear/core/cpp/logging_private.h" +#include "metawear/core/cpp/macro_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" +#include "metawear/core/cpp/settings_register.h" +#include "metawear/core/cpp/settings_private.h" +#include "metawear/core/cpp/timer_private.h" + +#include "metawear/platform/cpp/threadpool.h" + +#include "metawear/processor/cpp/dataprocessor_config.h" +#include "metawear/processor/cpp/dataprocessor_register.h" +#include "metawear/processor/cpp/dataprocessor_private.h" + +#include "metawear/sensor/accelerometer.h" +#include "metawear/sensor/gyro_bosch.h" +#include "metawear/sensor/sensor_fusion.h" + +#include "metawear/sensor/cpp/accelerometer_private.h" +#include "metawear/sensor/cpp/ambientlight_ltr329_private.h" +#include "metawear/sensor/cpp/barometer_bosch_private.h" +#include "metawear/sensor/cpp/colordetector_tcs34725_private.h" +#include "metawear/sensor/cpp/gpio_private.h" +#include "metawear/sensor/cpp/gpio_register.h" +#include "metawear/sensor/cpp/gyro_bosch_private.h" +#include "metawear/sensor/cpp/humidity_bme280_private.h" +#include "metawear/sensor/cpp/magnetometer_bmm150_private.h" +#include "metawear/sensor/cpp/multichanneltemperature_private.h" +#include "metawear/sensor/cpp/proximity_tsl2671_private.h" +#include "metawear/sensor/cpp/serialpassthrough_private.h" +#include "metawear/sensor/cpp/serialpassthrough_register.h" +#include "metawear/sensor/cpp/sensor_fusion_private.h" +#include "metawear/sensor/cpp/switch_private.h" +#include "metawear/sensor/cpp/conductance_private.h" + +using namespace std; +using namespace std::chrono; + +/** Constant signifying a module is not available */ +const int32_t MBL_MW_MODULE_TYPE_NA = -1; +const uint8_t CARTESIAN_FLOAT_SIZE= 6; +const uint16_t MAX_TIME_PER_RESPONSE= 4000; + +#define CLEAR_READ_MODIFIERS(x) (x & 0x3f) + +static MblMwDataProcessor* find_processor(MblMwDataProcessor* processor, DataProcessorType key) { + MblMwDataProcessor* value = processor; + while(value != nullptr) { + if (value->type == key) { + return value; + } + value = value->parent(); + } + + return nullptr; +} + +static int64_t extract_accounter_epoch(MblMwDataProcessor* processor, int64_t original_epoch, const uint8_t** start, uint8_t& len, uint32_t* tick) { + uint8_t timestampLength = get_accounter_length(processor); + // TODO: The logger uses a hardcoded prescaler of 3, upstream we force that value + // and assume it to be so here, eventually we will have a prescale aware timestamp + // API that works off of the base clock and call get_accounter_prescale(processor); + memcpy(tick, *start, timestampLength); + + (*start) += timestampLength; + len -= timestampLength; + + if (get_accounter_type(processor) == ACCOUNTER_TIME) { + return calculate_epoch(processor->owner, *tick); + } + + return original_epoch; +} + +static bool invoke_signal_handler(MblMwDataSignal* signal, int64_t epoch, const uint8_t* response, uint8_t len, void* extra) { + if (signal->handler != nullptr) { + MblMwData* data = data_response_converters.at(signal->interpreter)(false, signal, response, len); + data->epoch = epoch; + data->extra = extra; + signal->handler(signal->context, data); + + free_data(signal, data); + return true; + } + return false; +} + +static int32_t forward_response(const ResponseHeader& header, MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto it = board->module_events.find(header); + if (it == board->module_events.end()) { + return MBL_MW_STATUS_WARNING_UNEXPECTED_SENSOR_DATA; + } + + auto signal = dynamic_cast(it->second); + bool handled= false; + int64_t epoch = duration_cast(system_clock::now().time_since_epoch()).count(); + + MblMwDataProcessor* processor = dynamic_cast(signal); + const uint8_t* start = response; + uint32_t extra; + if (processor != nullptr) { + switch(processor->type) { + case DataProcessorType::ACCOUNTER: { + epoch = extract_accounter_epoch(processor, epoch, &start, len, &extra); + auto parent = find_processor(processor, DataProcessorType::PACKER); + + if (parent != nullptr) { + uint8_t i = 0, count = get_packer_count(parent), pack_size = get_packer_length(parent); + do { + handled|= invoke_signal_handler(signal, epoch, start, pack_size, &extra); + i++; + start+= pack_size; + } while(i < count); + return handled ? MBL_MW_STATUS_OK : MBL_MW_STATUS_WARNING_UNEXPECTED_SENSOR_DATA; + } + break; + } + case DataProcessorType::PACKER: { + auto parent = find_processor(processor, DataProcessorType::ACCOUNTER); + uint8_t i = 0, count = get_packer_count(processor), + pack_size = get_packer_length(processor) - (parent == nullptr ? 0 : get_accounter_length(parent)); + + do { + int64_t real_epoch = parent == nullptr ? epoch : extract_accounter_epoch(parent, epoch, &start, len, &extra); + handled|= invoke_signal_handler(signal, real_epoch, start, pack_size, &extra); + i++; + len-= pack_size; + start+= pack_size; + } while(i < count); + return handled ? MBL_MW_STATUS_OK : MBL_MW_STATUS_WARNING_UNEXPECTED_SENSOR_DATA; + } + default: + break; + } + } + + handled|= invoke_signal_handler(signal, epoch, start, len, &extra); + for(auto it: signal->components) { + handled|= invoke_signal_handler(it, epoch, start, len, &extra); + } + + return handled ? MBL_MW_STATUS_OK : MBL_MW_STATUS_WARNING_UNEXPECTED_SENSOR_DATA; +} + +int32_t response_handler_data_no_id(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + return forward_response(ResponseHeader(response[0], response[1]), board, response + 2, len - 2); +} + +int32_t response_handler_data_with_id(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + return forward_response(ResponseHeader(response[0], response[1], response[2]), board, response + 3, len - 3); +} + +int32_t response_handler_packed_data(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + ResponseHeader header(response[0], response[1]); + MblMwDataSignal* signal; + auto it = board->module_events.find(header); + + if (it == board->module_events.end() || (signal = dynamic_cast(it->second))->handler == nullptr) { + return MBL_MW_STATUS_WARNING_UNEXPECTED_SENSOR_DATA; + } + + int64_t now = duration_cast(system_clock::now().time_since_epoch()).count(); + for(uint8_t i= 2; i < len; i+= CARTESIAN_FLOAT_SIZE) { + MblMwData* data = data_response_converters.at(signal->interpreter)(false, signal, response + i, len - i); + data->epoch= now; + + if (signal->handler != nullptr) { + signal->handler(signal->context, data); + } + + free_data(signal, data); + } + + return MBL_MW_STATUS_OK; +} + +const uint8_t READ_INFO_REGISTER= READ_REGISTER(0x0); +const vector> MODULE_DISCOVERY_CMDS= { + {MBL_MW_MODULE_SWITCH, READ_INFO_REGISTER}, + {MBL_MW_MODULE_LED, READ_INFO_REGISTER}, + {MBL_MW_MODULE_ACCELEROMETER, READ_INFO_REGISTER}, + {MBL_MW_MODULE_TEMPERATURE, READ_INFO_REGISTER}, + {MBL_MW_MODULE_GPIO, READ_INFO_REGISTER}, + {MBL_MW_MODULE_NEO_PIXEL, READ_INFO_REGISTER}, + {MBL_MW_MODULE_IBEACON, READ_INFO_REGISTER}, + {MBL_MW_MODULE_HAPTIC, READ_INFO_REGISTER}, + {MBL_MW_MODULE_DATA_PROCESSOR, READ_INFO_REGISTER}, + {MBL_MW_MODULE_EVENT, READ_INFO_REGISTER}, + {MBL_MW_MODULE_LOGGING, READ_INFO_REGISTER}, + {MBL_MW_MODULE_TIMER, READ_INFO_REGISTER}, + {MBL_MW_MODULE_I2C, READ_INFO_REGISTER}, + {MBL_MW_MODULE_MACRO, READ_INFO_REGISTER}, + {MBL_MW_MODULE_CONDUCTANCE, READ_INFO_REGISTER}, + {MBL_MW_MODULE_SETTINGS, READ_INFO_REGISTER}, + {MBL_MW_MODULE_BAROMETER, READ_INFO_REGISTER}, + {MBL_MW_MODULE_GYRO, READ_INFO_REGISTER}, + {MBL_MW_MODULE_AMBIENT_LIGHT, READ_INFO_REGISTER}, + {MBL_MW_MODULE_MAGNETOMETER, READ_INFO_REGISTER}, + {MBL_MW_MODULE_HUMIDITY, READ_INFO_REGISTER}, + {MBL_MW_MODULE_COLOR_DETECTOR, READ_INFO_REGISTER}, + {MBL_MW_MODULE_PROXIMITY, READ_INFO_REGISTER}, + {MBL_MW_MODULE_SENSOR_FUSION, READ_INFO_REGISTER}, + {MBL_MW_MODULE_DEBUG, READ_INFO_REGISTER} +}; + +const unordered_map&)> CONFIG_SERIALIZATION = { + { MBL_MW_MODULE_ACCELEROMETER, serialize_accelerometer_config }, + { MBL_MW_MODULE_BAROMETER, serialize_barometer_config }, + { MBL_MW_MODULE_GYRO, serialize_gyro_config }, + { MBL_MW_MODULE_AMBIENT_LIGHT, serialize_ambient_light_config }, + { MBL_MW_MODULE_COLOR_DETECTOR, serialize_colordetector_config }, + { MBL_MW_MODULE_PROXIMITY, serialize_proximity_config }, + { MBL_MW_MODULE_SENSOR_FUSION, serialize_sensor_fusion_config } +}; +const unordered_map CONFIG_DESERIALIZATION = { + { MBL_MW_MODULE_ACCELEROMETER, deserialize_accelerometer_config }, + { MBL_MW_MODULE_BAROMETER, deserialize_barometer_config }, + { MBL_MW_MODULE_GYRO, deserialize_gyro_config }, + { MBL_MW_MODULE_AMBIENT_LIGHT, deserialize_ambient_light_config }, + { MBL_MW_MODULE_COLOR_DETECTOR, deserialize_colordetector_config }, + { MBL_MW_MODULE_PROXIMITY, deserialize_proximity_config }, + { MBL_MW_MODULE_SENSOR_FUSION, deserialize_sensor_fusion_config } +}; + +const MblMwGattChar METAWEAR_SERVICE_NOTIFY_CHAR = { 0x326a900085cb9195, 0xd9dd464cfbbae75a, 0x326a900685cb9195, 0xd9dd464cfbbae75a }; + +const uint64_t DEVICE_INFO_SERVICE_UUID_HIGH = 0x0000180a00001000, + DEVICE_INFO_SERVICE_UUID_LOW = 0x800000805f9b34fb; + +const MblMwGattChar METAWEAR_COMMAND_CHAR = { METAWEAR_SERVICE_NOTIFY_CHAR.service_uuid_high, METAWEAR_SERVICE_NOTIFY_CHAR.service_uuid_low, + 0x326a900185cb9195, 0xd9dd464cfbbae75a }; +const MblMwGattChar DEV_INFO_FIRMWARE_CHAR = { DEVICE_INFO_SERVICE_UUID_HIGH, DEVICE_INFO_SERVICE_UUID_LOW, 0x00002a2600001000, 0x800000805f9b34fb }, + DEV_INFO_MODEL_CHAR = { DEVICE_INFO_SERVICE_UUID_HIGH, DEVICE_INFO_SERVICE_UUID_LOW, 0x00002a2400001000, 0x800000805f9b34fb }, + DEV_INFO_HW_CHAR = { DEVICE_INFO_SERVICE_UUID_HIGH, DEVICE_INFO_SERVICE_UUID_LOW, 0x00002a2700001000, 0x800000805f9b34fb }, + DEV_INFO_MFT_CHAR = { DEVICE_INFO_SERVICE_UUID_HIGH, DEVICE_INFO_SERVICE_UUID_LOW, 0x00002a2900001000, 0x800000805f9b34fb }, + DEV_INFO_SERIAL_CHAR = { DEVICE_INFO_SERVICE_UUID_HIGH, DEVICE_INFO_SERVICE_UUID_LOW, 0x00002a2500001000, 0x800000805f9b34fb }; + +const vector> BOARD_DEV_INFO_CHARS = { + make_tuple(DEV_INFO_FIRMWARE_CHAR, [](MblMwMetaWearBoard* board, const uint8_t* value, uint8_t length) { + Version current(string(value, value + length)); + + if (!(board->firmware_revision == current)) { + board->firmware_revision = current; + + board->logger_state.reset(); + board->timer_state.reset(); + board->event_state.reset(); + board->dp_state.reset(); + board->macro_state.reset(); + board->debug_state.reset(); + free_accelerometer_module(board); + free_gyro_module(board); + free_sensor_fusion_module(board); + free_settings_module(board); + + for (auto it : board->module_events) { + it.second->remove = false; + delete it.second; + } + board->module_events.clear(); + + for (auto it : board->module_config) { + free(it.second); + } + board->module_config.clear(); + + board->module_info.clear(); + } + }, [](MblMwMetaWearBoard* board) { return false; }), + make_tuple(DEV_INFO_MODEL_CHAR, [](MblMwMetaWearBoard* board, const uint8_t* value, uint8_t length) { board->module_number.assign(value, value + length); }, + [](MblMwMetaWearBoard* board) { return !board->module_number.empty(); } + ), + make_tuple(DEV_INFO_HW_CHAR, [](MblMwMetaWearBoard* board, const uint8_t* value, uint8_t length) { board->hardware_revision.assign(value, value + length); }, + [](MblMwMetaWearBoard* board) { return !board->hardware_revision.empty(); } + ), + make_tuple(DEV_INFO_MFT_CHAR, [](MblMwMetaWearBoard* board, const uint8_t* value, uint8_t length) { board->manufacturer.assign(value, value + length); }, + [](MblMwMetaWearBoard* board) { return !board->manufacturer.empty(); } + ), + make_tuple(DEV_INFO_SERIAL_CHAR, [](MblMwMetaWearBoard* board, const uint8_t* value, uint8_t length) { board->serial_number.assign(value, value + length); }, + [](MblMwMetaWearBoard* board) { return !board->serial_number.empty(); } + ) +}; + +MblMwMetaWearBoard::MblMwMetaWearBoard() : logger_state(nullptr, [](void *ptr) -> void { tear_down_logging(ptr, false); }), + timer_state(nullptr, [](void *ptr) -> void { free_timer_module(ptr); }), + event_state(nullptr, [](void *ptr) -> void { free_event_module(ptr); }), + dp_state(nullptr, [](void *ptr) -> void { free_dataprocessor_module(ptr); }), + macro_state(nullptr, [](void *ptr) -> void { free_macro_module(ptr); }), + debug_state(nullptr, [](void *ptr) -> void { free_debug_module(ptr); }), + time_per_response(150), module_discovery_index(-1) { +} + +MblMwMetaWearBoard::~MblMwMetaWearBoard() { + logger_state.reset(); + timer_state.reset(); + event_state.reset(); + dp_state.reset(); + macro_state.reset(); + debug_state.reset(); + free_accelerometer_module(this); + free_gyro_module(this); + free_sensor_fusion_module(this); + free_settings_module(this); + + for (auto it: module_events) { + it.second->remove= false; + delete it.second; + } + + for (auto it: module_config) { + free(it.second); + } +} + +MblMwMetaWearBoard* mbl_mw_metawearboard_create(const MblMwBtleConnection *connection) { + auto new_board= new MblMwMetaWearBoard(); + memcpy(&new_board->btle_conn, connection, sizeof(MblMwBtleConnection)); + return new_board; +} + +void mbl_mw_metawearboard_free(MblMwMetaWearBoard *board) { + delete board; +} + +void mbl_mw_metawearboard_set_time_for_response(MblMwMetaWearBoard* board, uint16_t response_time_ms) { + board->time_per_response= response_time_ms > MAX_TIME_PER_RESPONSE ? MAX_TIME_PER_RESPONSE : response_time_ms; +} + +const unordered_map> MODULE_ATTRS = { + { MBL_MW_MODULE_SWITCH, make_tuple("Switch", init_switch_module) }, + { MBL_MW_MODULE_LED, make_tuple("Led", nullptr) }, + { MBL_MW_MODULE_ACCELEROMETER, make_tuple("Accelerometer", init_accelerometer_module) }, + { MBL_MW_MODULE_TEMPERATURE, make_tuple("Temperature", init_multichannel_temp_module) }, + { MBL_MW_MODULE_GPIO, make_tuple("Gpio", init_gpio_module) }, + { MBL_MW_MODULE_NEO_PIXEL, make_tuple("NeoPixel", nullptr) }, + { MBL_MW_MODULE_IBEACON, make_tuple("IBeacon", nullptr) }, + { MBL_MW_MODULE_HAPTIC, make_tuple("Haptic", nullptr) }, + { MBL_MW_MODULE_DATA_PROCESSOR, make_tuple("DataProcessor", init_dataprocessor_module) }, + { MBL_MW_MODULE_EVENT, make_tuple("Event", init_event_module) }, + { MBL_MW_MODULE_LOGGING, make_tuple("Logging", init_logging) }, + { MBL_MW_MODULE_TIMER, make_tuple("Timer", init_timer_module) }, + { MBL_MW_MODULE_I2C, make_tuple("SerialPassthrough", init_serialpassthrough_module) }, + { MBL_MW_MODULE_MACRO, make_tuple("Macro", init_macro_module) }, + { MBL_MW_MODULE_CONDUCTANCE, make_tuple("Conductance", init_conductance_module) }, + { MBL_MW_MODULE_SETTINGS, make_tuple("Settings", init_settings_module) }, + { MBL_MW_MODULE_BAROMETER, make_tuple("Barometer", init_barometer_module) }, + { MBL_MW_MODULE_GYRO, make_tuple("Gyro", init_gyro_module) }, + { MBL_MW_MODULE_AMBIENT_LIGHT, make_tuple("AmbientLight", init_ambient_light_module) }, + { MBL_MW_MODULE_MAGNETOMETER, make_tuple("Magnetometer", init_magnetometer_module) }, + { MBL_MW_MODULE_HUMIDITY, make_tuple("Humidity", init_humidity_module) }, + { MBL_MW_MODULE_COLOR_DETECTOR, make_tuple("Color", init_colordetector_module) }, + { MBL_MW_MODULE_PROXIMITY, make_tuple("Proximity", init_proximity_module) }, + { MBL_MW_MODULE_SENSOR_FUSION, make_tuple("SensorFusion", init_sensor_fusion_module) }, + { MBL_MW_MODULE_DEBUG, make_tuple("Debug", init_debug_module) } +}; + +static inline void service_discovery_completed(MblMwMetaWearBoard* board) { + for (auto it : MODULE_ATTRS) { + if (board->module_info.count(it.first) && board->module_info.at(it.first).present && get<1>(it.second) != nullptr) { + get<1>(it.second)(board); + } + } + + MblMwDataSignal *signal = mbl_mw_logging_get_time_data_signal(board); + if (signal != nullptr) { + mbl_mw_datasignal_subscribe(signal, board, [](void *context, const MblMwData* data) { + MblMwMetaWearBoard* board = static_cast(context); + if (board->initialized_timeout != nullptr) { + board->initialized_timeout->cancel(); + } + + mbl_mw_datasignal_unsubscribe(mbl_mw_logging_get_time_data_signal(board)); + + MblMwLoggingTime *time = static_cast(data->value); + mbl_mw_logging_set_reference_time(board, time->reset_uid, time->epoch); + mbl_mw_logging_set_latest_reset_uid(board, time->reset_uid); + + board->initialized(board->initialized_context, board, MBL_MW_STATUS_OK); + }); + mbl_mw_datasignal_read(signal); + } else { + if (board->initialized_timeout != nullptr) { + board->initialized_timeout->cancel(); + } + board->initialized(board->initialized_context, board, MBL_MW_STATUS_OK); + } +} + +static inline void queue_next_query(MblMwMetaWearBoard *board) { + do { + board->module_discovery_index++; + } while (board->module_discovery_index < (int8_t) MODULE_DISCOVERY_CMDS.size() && + board->module_info.count(MODULE_DISCOVERY_CMDS[board->module_discovery_index][0])); + + if (board->module_discovery_index >= (int8_t) MODULE_DISCOVERY_CMDS.size()) { + service_discovery_completed(board); + } else { + send_command(board, MODULE_DISCOVERY_CMDS[board->module_discovery_index].data(), + (uint8_t) MODULE_DISCOVERY_CMDS[board->module_discovery_index].size()); + } +} + +static int32_t char_changed_handler(const void* caller, const uint8_t* value, uint8_t length) { + MblMwMetaWearBoard* board = (MblMwMetaWearBoard*) caller; + ResponseHeader header(value[0], value[1]); + + if (board->responses.count(header)) { + return board->responses.at(header)(board, value, length); + } else if (header.register_id == READ_INFO_REGISTER) { + board->module_info.emplace(piecewise_construct, forward_as_tuple(value[0]), forward_as_tuple(value, length)); + queue_next_query(board); + return MBL_MW_STATUS_OK; + } else { + return MBL_MW_STATUS_WARNING_INVALID_RESPONSE; + } +} + +static int32_t read_gatt_char_handler(const void* caller, const uint8_t* value, uint8_t length); +static void queue_next_read(MblMwMetaWearBoard* board) { + do { + board->dev_info_index++; + } while (board->dev_info_index < (int8_t) BOARD_DEV_INFO_CHARS.size() && + get<2>(BOARD_DEV_INFO_CHARS[board->dev_info_index])(board)); + + if (board->dev_info_index >= (int8_t) BOARD_DEV_INFO_CHARS.size()) { + queue_next_query(board); + } else { + board->btle_conn.read_gatt_char(board->btle_conn.context, board, &get<0>(BOARD_DEV_INFO_CHARS[board->dev_info_index]), read_gatt_char_handler); + } +} + +static int32_t read_gatt_char_handler(const void* caller, const uint8_t* value, uint8_t length) { + auto board = (MblMwMetaWearBoard*) caller; + get<1>(BOARD_DEV_INFO_CHARS[board->dev_info_index])(board, value, length); + queue_next_read(board); + + return MBL_MW_STATUS_OK; +} + +static void enable_notify_ready(const void* caller, int32_t value) { + auto board = (MblMwMetaWearBoard*) caller; + + if (value == MBL_MW_STATUS_OK) { + board->dev_info_index = -1; + board->initialized_timeout= ThreadPool::schedule([board](void) { + board->initialized(board->initialized_context, board, MBL_MW_STATUS_ERROR_TIMEOUT); + }, (MODULE_DISCOVERY_CMDS.size() + BOARD_DEV_INFO_CHARS.size() + 1) * board->time_per_response); + queue_next_read(board); + } else { + board->initialized(board->initialized_context, board, MBL_MW_STATUS_ERROR_ENABLE_NOTIFY); + } +} + +const unordered_set MODULE_DISCONNECT_HANDLERS = { + disconnect_logging, + disconnect_timer, + disconnect_dataprocessor +}; + +static void disconnect_handler(const void* caller, int32_t value) { + auto board = (MblMwMetaWearBoard*) caller; + + for(auto it: MODULE_DISCONNECT_HANDLERS) { + it(board); + } +} + +void mbl_mw_metawearboard_initialize(MblMwMetaWearBoard *board, void *context, MblMwFnBoardPtrInt initialized) { + board->initialized_context = context; + board->initialized = initialized; + board->dev_info_index = -1; + board->module_discovery_index = -1; + + board->btle_conn.on_disconnect(board->btle_conn.context, board, disconnect_handler); + board->btle_conn.enable_notifications(board->btle_conn.context, board, &METAWEAR_SERVICE_NOTIFY_CHAR, char_changed_handler, enable_notify_ready); +} + +void mbl_mw_metawearboard_tear_down(MblMwMetaWearBoard *board) { + vector spawned_keys; + + tear_down_logging(board->logger_state.get(), true); + + for (auto it: board->module_events) { + if (it.second->header.module_id == MBL_MW_MODULE_DATA_PROCESSOR || it.second->header.module_id == MBL_MW_MODULE_TIMER) { + spawned_keys.push_back(it.first); + } else { + it.second->event_command_ids.clear(); + } + } + sort(spawned_keys.begin(), spawned_keys.end()); + for (auto it: spawned_keys) { + auto event= board->module_events.at(it); + + if (it.module_id == MBL_MW_MODULE_TIMER) { + dynamic_cast(event)->remove_from_board(); + } + + event->remove = false; + delete event; + + board->module_events.erase(it); + } + + uint8_t command[2]= { MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::REMOVE_ALL) }; + SEND_COMMAND; + + command[0]= MBL_MW_MODULE_EVENT; + command[1]= ORDINAL(EventRegister::REMOVE_ALL); + SEND_COMMAND; + + command[0]= MBL_MW_MODULE_LOGGING; + command[1]= ORDINAL(LoggingRegister::REMOVE_ALL); + SEND_COMMAND; +} + +void send_command(const MblMwMetaWearBoard* board, const uint8_t* command, uint8_t len) { + if (!record_command(board, command, len)) { + board->btle_conn.write_gatt_char( + board->btle_conn.context, + board, + command[0] == MBL_MW_MODULE_MACRO ? MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE : MBL_MW_GATT_CHAR_WRITE_WITHOUT_RESPONSE, + &METAWEAR_COMMAND_CHAR, command, len + ); + record_macro(board, command, len); + } +} + +int32_t mbl_mw_metawearboard_is_initialized(const MblMwMetaWearBoard *board) { + return board->module_discovery_index == (int8_t) MODULE_DISCOVERY_CMDS.size(); +} + +int32_t mbl_mw_metawearboard_lookup_module(const MblMwMetaWearBoard *board, MblMwModule module) { + auto it = board->module_info.find(module); + return it == board->module_info.end() || !it->second.present ? MBL_MW_MODULE_TYPE_NA : it->second.implementation; +} + +MblMwModel mbl_mw_metawearboard_get_model(const MblMwMetaWearBoard* board) { + if (board->module_number.empty()) { + return MBL_MW_MODEL_NA; + } + + if (board->module_number == "0") { + return MBL_MW_MODEL_METAWEAR_R; + } + if (board->module_number == "1") { + if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_BAROMETER) != MBL_MW_MODULE_TYPE_NA && + mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_AMBIENT_LIGHT) != MBL_MW_MODULE_TYPE_NA) { + return MBL_MW_MODEL_METAWEAR_RPRO; + } + return MBL_MW_MODEL_METAWEAR_RG; + } + if (board->module_number == "2") { + if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_MAGNETOMETER) != MBL_MW_MODULE_TYPE_NA) { + return MBL_MW_MODEL_METAWEAR_CPRO; + } + if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_PROXIMITY) != MBL_MW_MODULE_TYPE_NA) { + return MBL_MW_MODEL_METADETECT; + } + if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_HUMIDITY) != MBL_MW_MODULE_TYPE_NA) { + return MBL_MW_MODEL_METAENV; + } + return MBL_MW_MODEL_METAWEAR_C; + } + if (board->module_number == "3") { + return MBL_MW_MODEL_METAHEALTH; + } + if (board->module_number == "4") { + return MBL_MW_MODEL_METATRACKER; + } + if (board->module_number == "5") { + if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_AMBIENT_LIGHT) != MBL_MW_MODULE_TYPE_NA) { + return MBL_MW_MODEL_METAMOTION_R; + } else { + return MBL_MW_MODEL_METAMOTION_RL; + } + } + if (board->module_number == "6") { + return MBL_MW_MODEL_METAMOTION_C; + } + if (board->module_number == "8") { + return MBL_MW_MODEL_METAMOTION_S; + } + + + return MBL_MW_MODEL_NA; +} + +const char * MODEL_NAMES[] = { + "Unknown", + "MetaWear R", + "MetaWear RG", + "MetaWear RPro", + "MetaWear C", + "MetaWear CPro", + "MetaEnvironment", + "MetaDetector", + "MetaHealth", + "MetaTracker", + "MetaMotion R", + "MetaMotion RL", + "MetaMotion C", + "MetaMotion S" +}; +const char* mbl_mw_metawearboard_get_model_name(const MblMwMetaWearBoard* board) { + return MODEL_NAMES[mbl_mw_metawearboard_get_model(board) + 1]; +} + +const MblMwDeviceInformation* mbl_mw_metawearboard_get_device_information(const MblMwMetaWearBoard* board) { + MblMwDeviceInformation* dev_info = (MblMwDeviceInformation*) malloc(sizeof(MblMwDeviceInformation)); + dev_info->manufacturer = board->manufacturer.c_str(); + dev_info->model_number = board->module_number.c_str(); + dev_info->serial_number = board->serial_number.c_str(); + dev_info->firmware_revision = board->firmware_revision.sem_ver.c_str(); + dev_info->hardware_revision = board->hardware_revision.c_str(); + return dev_info; +} + +MblMwModuleInfo* mbl_mw_metawearboard_get_module_info(const MblMwMetaWearBoard* board, uint32_t* size) { + *size = static_cast(board->module_info.size()); + MblMwModuleInfo* info = (MblMwModuleInfo*) malloc(sizeof(MblMwModuleInfo) * (*size)); + + vector sorted_keys; + for (auto it : board->module_info) { + sorted_keys.push_back(it.first); + } + sort(sorted_keys.begin(), sorted_keys.end()); + + auto temp = info; + for(auto it: sorted_keys) { + auto value = &board->module_info.at(it); + temp->name = get<0>(MODULE_ATTRS.at(it)); + temp->extra = value->extra.data(); + temp->extra_len = value->extra.size(); + temp->present = value->present ? 1 : 0; + temp->implementation = value->implementation; + temp->revision = value->revision; + temp++; + } + + return info; +} + +uint8_t* mbl_mw_metawearboard_serialize(const MblMwMetaWearBoard* board, uint32_t* size) { + vector serialized_state; + + serialized_state.push_back(ORDINAL(SerializationFormat::TIME_REFERENCE)); + + board->firmware_revision.serialize(serialized_state); + + serialized_state.push_back((uint8_t)board->module_number.size()); + serialized_state.insert(serialized_state.end(), board->module_number.begin(), board->module_number.end()); + + { + vector sorted_keys; + for (auto it : board->module_info) { + sorted_keys.push_back(it.first); + } + sort(sorted_keys.begin(), sorted_keys.end()); + + serialized_state.push_back((uint8_t)board->module_info.size()); + for (auto it : sorted_keys) { + board->module_info.at(it).serialize(serialized_state); + } + } + + { + uint8_t n_events= 0; + vector event_states; + vector sorted_keys; + for (auto it : board->module_events) { + sorted_keys.emplace_back(it.first.module_id, it.first.register_id, it.first.data_id); + } + sort(sorted_keys.begin(), sorted_keys.end()); + + for (auto it : sorted_keys) { + board->module_events.at(it)->serialize(event_states); + n_events++; + + // serialize component signals after the main signal + // rely on this ordering to restore the components vector + if (MblMwDataSignal* signal= dynamic_cast(board->module_events.at(it))) { + for(auto component: signal->components) { + component->serialize(event_states); + n_events++; + } + } + } + + serialized_state.push_back(n_events); + serialized_state.insert(serialized_state.end(), event_states.begin(), event_states.end()); + } + + { + vector sorted_keys; + for (auto it : board->module_config) { + sorted_keys.push_back(it.first); + } + sort(sorted_keys.begin(), sorted_keys.end()); + + serialized_state.push_back((uint8_t)board->module_config.size()); + for (auto it : sorted_keys) { + if (CONFIG_SERIALIZATION.count(it)) { + serialized_state.push_back(it); + CONFIG_SERIALIZATION.at(it)(board, serialized_state); + } + } + } + + serialize_logging(board, serialized_state); + + *size = (uint32_t) serialized_state.size(); + uint8_t* state_bytes = (uint8_t*)malloc(sizeof(uint8_t) * (*size)); + memcpy(state_bytes, serialized_state.data(), *size); + return state_bytes; +} + +int32_t mbl_mw_metawearboard_deserialize(MblMwMetaWearBoard* board, uint8_t* state, uint32_t size) { + uint8_t *current_addr = state, format = *current_addr; + + if (format > ORDINAL(SerializationFormat::TIME_REFERENCE)) { + return MBL_MW_STATUS_ERROR_SERIALIZATION_FORMAT; + } + + board->firmware_revision.deserialize(&(++current_addr)); + + uint8_t module_str_size = *current_addr; + current_addr++; + board->module_number.assign(current_addr, current_addr + module_str_size); + current_addr += module_str_size; + + board->module_info.clear(); + uint8_t module_info_size = *current_addr; + current_addr++; + for (uint8_t i = 0; i < module_info_size; i++) { + board->module_info.emplace(*current_addr, ¤t_addr); + } + + for (auto it : board->module_events) { + delete it.second; + } + board->module_events.clear(); + + uint8_t n_events = *current_addr; + current_addr++; + for (uint8_t i = 0; i < n_events; i++) { + MblMwEvent* saved_event; + + switch (*current_addr) { + case MBL_MW_MODULE_GPIO: + switch(static_cast(CLEAR_READ_MODIFIERS(*(current_addr + 1)))) { + case GpioRegister::READ_AI_ABS_REF: + case GpioRegister::READ_AI_ADC: + saved_event= new MblMwGpioAnalogSignal(¤t_addr, board); + break; + case GpioRegister::PIN_CHANGE_NOTIFY: + saved_event= new MblMwGpioPinNotifySignal(¤t_addr, board); + break; + default: + saved_event = new MblMwDataSignal(¤t_addr, board); + break; + } + break; + case MBL_MW_MODULE_DATA_PROCESSOR: + saved_event = static_cast(CLEAR_READ_MODIFIERS(*(current_addr + 1))) == DataProcessorRegister::STATE ? + new MblMwDataSignal(¤t_addr, board) : + new MblMwDataProcessor(¤t_addr, board); + break; + case MBL_MW_MODULE_TIMER: + saved_event = new MblMwTimer(¤t_addr, board); + break; + case MBL_MW_MODULE_I2C: + switch(static_cast(CLEAR_READ_MODIFIERS(*(current_addr + 1)))) { + case SerialPassthroughRegister::I2C_READ_WRITE: + saved_event= new MblMwI2cSignal(¤t_addr, board); + break; + case SerialPassthroughRegister::SPI_READ_WRITE: + saved_event= new MblMwSpiSignal(¤t_addr, board); + break; + default: + saved_event= new MblMwDataSignal(¤t_addr, board); + break; + } + break; + case MBL_MW_MODULE_SETTINGS: + saved_event = static_cast(*(current_addr + 1)) == SettingsRegister::DISCONNECT_EVENT ? + new MblMwEvent(¤t_addr, board) : + new MblMwDataSignal(¤t_addr, board); + break; + default: + saved_event = new MblMwDataSignal(¤t_addr, board); + break; + } + + ResponseHeader live_header(saved_event->header); + live_header.disable_silent(); + + if (board->module_events.count(live_header)) { + auto signal = dynamic_cast(board->module_events[live_header]); + signal->components.push_back(dynamic_cast(saved_event)); + } else { + board->module_events.emplace(live_header, saved_event); + } + } + + uint8_t module_config_size= *current_addr; + current_addr++; + for (uint8_t i= 0; i < module_config_size; i++) { + if (CONFIG_DESERIALIZATION.count(*current_addr)) { + auto fn = CONFIG_DESERIALIZATION.at(*current_addr); + current_addr++; + fn(board, ¤t_addr); + } + } + + deserialize_logging(board, format, ¤t_addr); + + return MBL_MW_STATUS_OK; +} + +static bool has_suffix(const std::string &str, const std::string &suffix) { + return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; +} + +static int32_t dfu_char_changed_handler(const void* caller, const uint8_t* value, uint8_t length) { + ((MblMwMetaWearBoard*) caller)->operations->processDFUResponse(value, length); + return MBL_MW_STATUS_OK; +} + +static void dfu_enable_notify_ready(const void* caller, int32_t value) { + auto board = (MblMwMetaWearBoard*) caller; + + if (value == MBL_MW_STATUS_OK) { + if (has_suffix(board->filename, "zip")) { + board->operations->perfromDFUOnZipFile(board->filename); + } else { + board->operations->performOldDFUOnFile(board->filename); + } + } else { + board->operations->cancelDFU(); + } +} + +void mbl_mw_metawearboard_perform_dfu(MblMwMetaWearBoard *board, const MblMwDfuDelegate *delegate, const char *filename) { + board->operations.reset(new DfuOperations(board, delegate)); + board->filename = filename; + board->btle_conn.enable_notifications(board->btle_conn.context, board, &DFU_CONTROL_POINT_CHAR, dfu_char_changed_handler, dfu_enable_notify_ready); +} + +static void read_sensor_fusion_config_completed(void *context, MblMwMetaWearBoard* board, int32_t value) { + query_active_loggers(board); +} + +static void read_gyro_config_completed(void *context, MblMwMetaWearBoard* board, int32_t value) { + if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_SENSOR_FUSION) != MBL_MW_MODULE_TYPE_NA) { + mbl_mw_sensor_fusion_read_config(board, context, read_sensor_fusion_config_completed); + } else { + read_sensor_fusion_config_completed(context, board, MBL_MW_STATUS_OK); + } +} + +static void read_acc_config_completed(void *context, MblMwMetaWearBoard* board, int32_t value) { + if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_GYRO) != MBL_MW_MODULE_TYPE_NA) { + mbl_mw_gyro_bmi160_read_config(board, context, read_gyro_config_completed); + } else { + read_gyro_config_completed(context, board, MBL_MW_STATUS_OK); + } +} + +void mbl_mw_metawearboard_create_anonymous_datasignals(MblMwMetaWearBoard* board, void *context, MblMwFnAnonSignalArray created) { + board->anon_signals_context = context; + board->anon_signals_created = created; + mbl_mw_acc_read_config(board, context, read_acc_config_completed); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/haptic.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/haptic.cpp new file mode 100644 index 0000000..e92a64b --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/haptic.cpp @@ -0,0 +1,23 @@ +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/peripheral/haptic.h" + +#include + +static const uint8_t HAPTIC_MODULE= 0x8; +static const uint8_t HAPTIC_PULSE= 0x1; +static const uint8_t BUZZER_DUTY_CYCLE= 127; + +void mbl_mw_haptic_start_motor(const MblMwMetaWearBoard *board, float duty_cycle_per, uint16_t pulse_width_ms) { + uint8_t converted= uint8_t ((duty_cycle_per / 100.f) * 248); + uint8_t command[6]= {HAPTIC_MODULE, HAPTIC_PULSE, converted, 0, 0, 0}; + + std::memcpy(command + 3, &pulse_width_ms, 2); + SEND_COMMAND; +} + +void mbl_mw_haptic_start_buzzer(const MblMwMetaWearBoard *board, uint16_t pulse_width_ms) { + uint8_t command[6]= {HAPTIC_MODULE, HAPTIC_PULSE, BUZZER_DUTY_CYCLE, 0, 0, 1}; + + std::memcpy(command + 3, &pulse_width_ms, 2); + SEND_COMMAND; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/ibeacon.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/ibeacon.cpp new file mode 100644 index 0000000..b607559 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/ibeacon.cpp @@ -0,0 +1,70 @@ +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" + +#include "metawear/peripheral/ibeacon.h" + +#include + +static const uint8_t IBEACON_MODULE = 0x7; + +static const uint8_t IBEACON_ENABLE = 0x1, IBEACON_UUID = 0x2, IBEACON_MAJOR = 0x3, IBEACON_MINOR = 0x4, +IBEACON_RX = 0x5, IBEACON_TX = 0x6, IBEACON_PERIOD = 0x7; + +#define SET_PARAM_NBYTES(reg, addr, len)\ + uint8_t command[len + 2]= {IBEACON_MODULE, reg};\ + std::memcpy(command + 2, addr, len);\ + SEND_COMMAND; + +#define SET_PARAM_USHORT(reg, addr) SET_PARAM_NBYTES(reg, addr, 2) + +#define SET_PARAM_UBYTE(reg, value)\ + uint8_t command[3]= {IBEACON_MODULE, reg, value};\ + SEND_COMMAND; + +void mbl_mw_ibeacon_set_major(const MblMwMetaWearBoard *board, uint16_t major) { + SET_PARAM_USHORT(IBEACON_MAJOR, &major); +} + +void mbl_mw_ibeacon_set_major_signal(MblMwMetaWearBoard *board, const MblMwDataSignal* major) { + EventDataParameter signal_data_token= {major->length(), major->offset, 0}; + + set_data_token(board, &signal_data_token); + mbl_mw_ibeacon_set_major(board, 0); + clear_data_token(board); +} + +void mbl_mw_ibeacon_set_minor(const MblMwMetaWearBoard *board, uint16_t minor) { + SET_PARAM_USHORT(IBEACON_MINOR, &minor); +} + +void mbl_mw_ibeacon_set_minor_signal(MblMwMetaWearBoard *board, const MblMwDataSignal* minor) { + EventDataParameter signal_data_token= {minor->length(), minor->offset, 0}; + + set_data_token(board, &signal_data_token); + mbl_mw_ibeacon_set_minor(board, 0); + clear_data_token(board); +} + +void mbl_mw_ibeacon_set_period(const MblMwMetaWearBoard *board, uint16_t period) { + SET_PARAM_USHORT(IBEACON_PERIOD, &period); +} + +void mbl_mw_ibeacon_set_tx_power(const MblMwMetaWearBoard *board, int8_t tx_power) { + SET_PARAM_UBYTE(IBEACON_TX, static_cast(tx_power)); +} + +void mbl_mw_ibeacon_set_rx_power(const MblMwMetaWearBoard *board, int8_t rx_power) { + SET_PARAM_UBYTE(IBEACON_RX, static_cast(rx_power)); +} + +void mbl_mw_ibeacon_set_uuid(const MblMwMetaWearBoard *board, uint8_t ad_uuid[16]) { + SET_PARAM_NBYTES(IBEACON_UUID, ad_uuid, 16); +} + +void mbl_mw_ibeacon_enable(const MblMwMetaWearBoard *board) { + SET_PARAM_UBYTE(IBEACON_ENABLE, 1); +} + +void mbl_mw_ibeacon_disable(const MblMwMetaWearBoard *board) { + SET_PARAM_UBYTE(IBEACON_ENABLE, 0); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/led.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/led.cpp new file mode 100644 index 0000000..82606f7 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/led.cpp @@ -0,0 +1,75 @@ +#include "metawear/core/module.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/peripheral/led.h" + +#include + +using namespace std; + +const uint8_t LED_PLAY= 1, LED_STOP= 2, LED_CONFIG= 3, DELAYED_REVISION= 1; + +static inline void set_intensities(MblMwLedPattern *pattern, uint8_t high, uint8_t low) { + pattern->high_intensity= high; + pattern->low_intensity= low; +} + +static inline void set_pulse_times(MblMwLedPattern *pattern, uint16_t rise_ms, uint16_t high_ms, uint16_t fall_ms, uint16_t duration_ms) { + pattern->rise_time_ms= rise_ms; + pattern->high_time_ms= high_ms; + pattern->fall_time_ms= fall_ms; + pattern->pulse_duration_ms= duration_ms; +} + +void mbl_mw_led_load_preset_pattern(MblMwLedPattern* pattern, MblMwLedPreset preset) { + switch (preset) { + case MBL_MW_LED_PRESET_BLINK: + set_intensities(pattern, 31, 0); + set_pulse_times(pattern, 0, 50, 0, 500); + break; + case MBL_MW_LED_PRESET_PULSE: + set_intensities(pattern, 31, 0); + set_pulse_times(pattern, 725, 500, 725, 2000); + break; + case MBL_MW_LED_PRESET_SOLID: + set_intensities(pattern, 31, 31); + set_pulse_times(pattern, 0, 500, 0, 1000); + break; + } +} + +void mbl_mw_led_write_pattern(const MblMwMetaWearBoard *board, const MblMwLedPattern *pattern, MblMwLedColor color) { + uint8_t command[17]= { MBL_MW_MODULE_LED, LED_CONFIG, static_cast(color), 2}; + + // MblMwLedPattern is aligned to 14 bytes wide, individual elements total to 13 bytes + memcpy(command + 4, pattern, 13); + if (board->module_info.at(MBL_MW_MODULE_LED).revision < DELAYED_REVISION) { + command[14]= 0; + command[15]= 0; + } + SEND_COMMAND; +} + +void mbl_mw_led_autoplay(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_LED, LED_PLAY, 2}; + SEND_COMMAND; +} + +void mbl_mw_led_play(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_LED, LED_PLAY, 1}; + SEND_COMMAND; +} + +void mbl_mw_led_pause(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_LED, LED_PLAY, 0}; + SEND_COMMAND; +} + +void mbl_mw_led_stop(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_LED, LED_STOP, 0}; + SEND_COMMAND; +} + +void mbl_mw_led_stop_and_clear(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_LED, LED_STOP, 1}; + SEND_COMMAND; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/neopixel.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/neopixel.cpp new file mode 100644 index 0000000..1363a0d --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/neopixel.cpp @@ -0,0 +1,71 @@ +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/peripheral/neopixel.h" + +#include + +static const uint8_t NEOPIXEL_MODULE= 6; +static const uint8_t NEOPIXEL_INITIALIZE= 1, NEOPIXEL_HOLD= 2, NEOPIXEL_CLEAR= 3, NEOPIXEL_PIXEL= 4, + NEOPIXEL_ROTATE= 5, NEOPIXEL_DEINITIALIZE= 6; + +static const uint8_t SPEED_SLOW= 0, SPEED_FAST= 1; +static const uint8_t HOLD_ENABLE= 1, HOLD_DISABLE= 0; + +static const uint8_t ROTATE_INDEFINITELY= 0xff; + +static void inline init_strand(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t gpio_pin, uint8_t n_pixels, uint8_t speed, MblMwNeoPixelColorOrdering ordering) { + uint8_t command[6]= {NEOPIXEL_MODULE, NEOPIXEL_INITIALIZE, strand, static_cast(ordering | (speed << 2)), gpio_pin, n_pixels}; + SEND_COMMAND; +} + +void mbl_mw_neopixel_init_slow_strand(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t gpio_pin, uint8_t n_pixels, MblMwNeoPixelColorOrdering ordering) { + init_strand(board, strand, gpio_pin, n_pixels, SPEED_SLOW, ordering); +} + +void mbl_mw_neopixel_init_fast_strand(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t gpio_pin, uint8_t n_pixels, MblMwNeoPixelColorOrdering ordering) { + init_strand(board, strand, gpio_pin, n_pixels, SPEED_FAST, ordering); +} + +void mbl_mw_neopixel_free_strand(const MblMwMetaWearBoard *board, uint8_t strand) { + uint8_t command[3]= {NEOPIXEL_MODULE, NEOPIXEL_DEINITIALIZE, strand}; + SEND_COMMAND; +} + +void mbl_mw_neopixel_enable_hold(const MblMwMetaWearBoard *board, uint8_t strand) { + uint8_t command[4]= {NEOPIXEL_MODULE, NEOPIXEL_HOLD, strand, HOLD_ENABLE}; + SEND_COMMAND; +} + +void mbl_mw_neopixel_disable_hold(const MblMwMetaWearBoard *board, uint8_t strand) { + uint8_t command[4]= {NEOPIXEL_MODULE, NEOPIXEL_HOLD, strand, HOLD_DISABLE}; + SEND_COMMAND; +} + +void mbl_mw_neopixel_clear(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t start, uint8_t end) { + uint8_t command[5]= {NEOPIXEL_MODULE, NEOPIXEL_CLEAR, strand, start, end}; + SEND_COMMAND; +} + +void mbl_mw_neopixel_set_color(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t pixel, uint8_t red, uint8_t green, uint8_t blue) { + uint8_t command[7]= {NEOPIXEL_MODULE, NEOPIXEL_PIXEL, strand, pixel, red, green, blue}; + SEND_COMMAND; +} + +void mbl_mw_neopixel_rotate(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t count, uint16_t period_ms, MblMwNeoPixelRotDirection direction) { + uint8_t command[7]= {NEOPIXEL_MODULE, NEOPIXEL_ROTATE, strand, + static_cast((direction != MBL_MW_NP_ROT_DIR_TOWARDS) ? MBL_MW_NP_ROT_DIR_AWAY : MBL_MW_NP_ROT_DIR_TOWARDS), + count}; + + memcpy(command + 5, &period_ms, 2); + SEND_COMMAND; +} + +void mbl_mw_neopixel_rotate_indefinitely(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t period_ms, MblMwNeoPixelRotDirection direction) { + mbl_mw_neopixel_rotate(board, strand, ROTATE_INDEFINITELY, period_ms, direction); +} + +void mbl_mw_neopixel_stop_rotation(const MblMwMetaWearBoard *board, uint8_t strand) { + uint8_t command[7]= {NEOPIXEL_MODULE, NEOPIXEL_ROTATE, strand}; + + std::memset(command + 3, 0, 4); + SEND_COMMAND; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/haptic.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/haptic.h new file mode 100644 index 0000000..3e1356d --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/haptic.h @@ -0,0 +1,33 @@ +/** + * @copyright MbientLab License + * @file haptic.h + * @brief Communicates with the haptic driver + */ +#pragma once + +#include "peripheral_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Drives a motor - Pulls down the HCD pin + * The MetaWear has a driver for motor or buzzers that are 3C compatible (check the datasheet) + * This is not a full PWM driver. + * @param board Pointer to the board to send the command to + * @param duty_cycle_per Strength of the motor, between [0, 100] percent + * @param pulse_width_ms How long to run the motor, in milliseconds + */ +METAWEAR_API void mbl_mw_haptic_start_motor(const MblMwMetaWearBoard *board, float duty_cycle_per, uint16_t pulse_width_ms); +/** + * Drives a buzzer - Pulls down the HCD pin + * The MetaWear has a driver for motor or buzzers that are 3C compatible (check the datasheet) + * @param board Pointer to the board to send the command to + * @param pulse_width_ms How long to run the buzzer, in milliseconds + */ +METAWEAR_API void mbl_mw_haptic_start_buzzer(const MblMwMetaWearBoard *board, uint16_t pulse_width_ms); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/ibeacon.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/ibeacon.h new file mode 100644 index 0000000..e8f17f6 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/ibeacon.h @@ -0,0 +1,78 @@ +/** + * @copyright MbientLab License + * @file ibeacon.h + * @brief Configures iBeacon mode + */ +#pragma once + +#include "peripheral_common.h" + +#include "metawear/core/datasignal_fwd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Sets the iBeacon advertising major number + * @param board Pointer to the board to send the command to + * @param major New advertising major number + */ +METAWEAR_API void mbl_mw_ibeacon_set_major(const MblMwMetaWearBoard *board, uint16_t major); +/** + * Sets the iBeacon advertising major number + * @param board Pointer to the board to send the command to + * @param major DataSignal output to use as the new major number + */ +METAWEAR_API void mbl_mw_ibeacon_set_major_signal(MblMwMetaWearBoard *board, const MblMwDataSignal* major); +/** + * Sets the iBeacon advertising minor number + * @param board Pointer to the board to send the command to + * @param minor New advertising minor number + */ +METAWEAR_API void mbl_mw_ibeacon_set_minor(const MblMwMetaWearBoard *board, uint16_t minor); +/** + * Sets the iBeacon advertising minor number + * @param board Pointer to the board to send the command to + * @param minor DataSignal output to use as the new minor number + */ +METAWEAR_API void mbl_mw_ibeacon_set_minor_signal(MblMwMetaWearBoard *board, const MblMwDataSignal* minor); +/** + * Sets the iBeacon advertising period + * @param board Pointer to the board to send the command to + * @param period New advertising period, in milliseconds + */ +METAWEAR_API void mbl_mw_ibeacon_set_period(const MblMwMetaWearBoard *board, uint16_t period); +/** + * Sets the iBeacon advertising transmitting power + * @param board Pointer to the board to send the command to + * @param tx_power New advertising transmitting power + */ +METAWEAR_API void mbl_mw_ibeacon_set_tx_power(const MblMwMetaWearBoard *board, int8_t tx_power); +/** + * Sets the iBeacon advertising receiving power + * @param board Pointer to the board to send the command to + * @param rx_power New advertising receiving power + */ +METAWEAR_API void mbl_mw_ibeacon_set_rx_power(const MblMwMetaWearBoard *board, int8_t rx_power); +/** + * Sets the iBeacon advertising UUID + * @param board Pointer to the board to send the command to + * @param ad_uuid Byte representation of the UUID in little endian ordering + */ +METAWEAR_API void mbl_mw_ibeacon_set_uuid(const MblMwMetaWearBoard *board, uint8_t ad_uuid[16]); +/** + * Enables iBeacon mode. You will need to disconnect from the board to + * advertise as an iBeacon + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_ibeacon_enable(const MblMwMetaWearBoard *board); +/** + * Disables iBeacon mode + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_ibeacon_disable(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/led.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/led.h new file mode 100644 index 0000000..e6f094a --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/led.h @@ -0,0 +1,92 @@ +/** + * @copyright MbientLab License + * @file led.h + * @brief Communicates with the ultra-bright LED + */ +#pragma once + +#include "peripheral_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Value indicating the led pulse will repeat indefinitely */ +const uint8_t MBL_MW_LED_REPEAT_INDEFINITELY = 0xff; + +/** + * Available colors on the LED + */ +typedef enum { + MBL_MW_LED_COLOR_GREEN, + MBL_MW_LED_COLOR_RED, + MBL_MW_LED_COLOR_BLUE +} MblMwLedColor; + +/** + * Enumeration of preset patterns available in the library + * Patterns are based on the led blog post, http://projects.mbientlab.com/?p=656 + */ +typedef enum { + MBL_MW_LED_PRESET_BLINK, + MBL_MW_LED_PRESET_PULSE, + MBL_MW_LED_PRESET_SOLID +} MblMwLedPreset; + +/** + * Attributes describing a light pulse + */ +typedef struct { + uint8_t high_intensity; ///< Intensity when the pulse is in a high state, between [0, 31] + uint8_t low_intensity; ///< Intensity when the pulse is in a low state, between [0, 31] + uint16_t rise_time_ms; ///< Transition time from low to high state, in milliseconds + uint16_t high_time_ms; ///< Length of time the pulse spends in the high state, in milliseconds + uint16_t fall_time_ms; ///< Transition time from high to low state, in milliseconds + uint16_t pulse_duration_ms; ///< Length of time for one pulse, in milliseconds + uint16_t delay_time_ms; ///< How long to wait before starting the pulse, only used on firmware v1.2.3 or later + uint8_t repeat_count; ///< Number of repetitions +} MblMwLedPattern; + +/** + * Loads the struct with a preset configuration + * @param pattern Pointer to the pattern to write the configuration to + * @param preset Preset pattern to load + */ +METAWEAR_API void mbl_mw_led_load_preset_pattern(MblMwLedPattern* pattern, MblMwLedPreset preset); + +/** + * Writes the led pattern to the board + * @param board Pointer to the board to send the command to + * @param pattern Pointer to the pattern attributes to write to the board + * @param color Color the pattern is configuring + */ +METAWEAR_API void mbl_mw_led_write_pattern(const MblMwMetaWearBoard* board, const MblMwLedPattern* pattern, MblMwLedColor color); +/** + * Plays any programmed patterns, and immediately plays any patterns programmed later + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_led_autoplay(const MblMwMetaWearBoard* board); +/** + * Plays any programmed patterns + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_led_play(const MblMwMetaWearBoard *board); +/** + * Pauses the patterns + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_led_pause(const MblMwMetaWearBoard *board); +/** + * Stops playing LED patterns + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_led_stop(const MblMwMetaWearBoard *board); +/** + * Stops playing LED patterns and clears all pattern configurations + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_led_stop_and_clear(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/neopixel.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/neopixel.h new file mode 100644 index 0000000..d26a501 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/neopixel.h @@ -0,0 +1,116 @@ +/** + * @copyright MbientLab License + * @file neopixel.h + * @brief Interacts with NeoPixel strands + */ +#pragma once + +#include "peripheral_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Color ordering for the NeoPixel color values + */ +typedef enum { + MBL_MW_NP_WS2811_RGB= 0, ///< Red, green, blue order + MBL_MW_NP_WS2811_RBG, ///< Red, blue, green order + MBL_MW_NP_WS2811_GRB, ///< Green, red, blue order + MBL_MW_NP_WS2811_GBR ///< Green, blue, red order +} MblMwNeoPixelColorOrdering; + +/** + * Enumeration of rotation directions + */ +typedef enum { + MBL_MW_NP_ROT_DIR_TOWARDS, ///< Pixels move towards the board + MBL_MW_NP_ROT_DIR_AWAY ///< Pixels move away from the board +} MblMwNeoPixelRotDirection; + +/** + * Initializes memory on the MetaWear board for a NeoPixel strand with a slow operating speed (400 KHz) + * @param board Pointer to the board to send the command to + * @param strand Strand number (id) to initialize, can be in the range [0, 2] + * @param ordering Color ordering format + * @param gpio_pin GPIO pin the strand's data pin is connected to + * @param n_pixels Number of pixels to allocate memory for + */ +METAWEAR_API void mbl_mw_neopixel_init_slow_strand(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t gpio_pin, uint8_t n_pixels, + MblMwNeoPixelColorOrdering ordering); +/** + * Initializes memory on the MetaWear board for a NeoPixel strand with a fast operating speed (800 KHz) + * @param board Pointer to the board to send the command to + * @param strand Strand number (id) to initialize, can be in the range [0, 2] + * @param ordering Color ordering format + * @param gpio_pin GPIO pin the strand's data pin is connected to + * @param n_pixels Number of pixels to allocate memory for + */ +METAWEAR_API void mbl_mw_neopixel_init_fast_strand(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t gpio_pin, uint8_t n_pixels, + MblMwNeoPixelColorOrdering ordering); +/** + * Frees NeoPixel resources on the MetaWeard board for a specific strand + * @param board Pointer to the board to send the command to + * @param strand Strand index to free + */ +METAWEAR_API void mbl_mw_neopixel_free_strand(const MblMwMetaWearBoard *board, uint8_t strand); +/** + * Enables strand holding which will not refresh with any LED changes until the hold is disabled. + * This let you to form complex LED patterns without having the strand refresh with partial changes. + * @param board Pointer to the board to send the command to + * @param strand Strand number (id) to hold + */ +METAWEAR_API void mbl_mw_neopixel_enable_hold(const MblMwMetaWearBoard *board, uint8_t strand); +/** + * Disables strand holding. The strand will be refreshed with any LED changes programmed + * while the hold was active + * @param board Pointer to the board to send the command to + * @param strand Strand number (id) to release + */ +METAWEAR_API void mbl_mw_neopixel_disable_hold(const MblMwMetaWearBoard *board, uint8_t strand); +/** + * Clears pixel states on a strand + * @param board Pointer to the board to send the command to + * @param strand Strand number to clear + * @param start Pixel index to start clearing from + * @param end Pixel index to clear to, inclusive + */ +METAWEAR_API void mbl_mw_neopixel_clear(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t start, uint8_t end); +/** + * Sets pixel color + * @param board Pointer to the board to send the command to + * @param strand Strand number the pixel is on + * @param pixel Index of the pixel + * @param red Red value, between [0, 255] + * @param green Green value, between [0, 255] + * @param blue Blue value, between [0, 255] + */ +METAWEAR_API void mbl_mw_neopixel_set_color(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t pixel, uint8_t red, uint8_t green, uint8_t blue); +/** + * Rotates the pixels on a strand + * @param board Pointer to the board to send the command to + * @param strand Strand to rotate + * @param direction Rotation direction + * @param count Number of times to repeat the rotation + * @param period_ms Amount of time, in milliseconds, between rotations + */ +METAWEAR_API void mbl_mw_neopixel_rotate(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t count, uint16_t period_ms, MblMwNeoPixelRotDirection direction); +/** + * Rotates the pixels on a strand indefinitely + * @param board Pointer to the board to send the command to + * @param strand Strand to rotate + * @param direction Rotation direction + * @param period_ms Amount of time, in milliseconds, between rotations + */ +METAWEAR_API void mbl_mw_neopixel_rotate_indefinitely(const MblMwMetaWearBoard *board, uint8_t strand, uint8_t period_ms, MblMwNeoPixelRotDirection direction); +/** + * Stops the pixel rotation + * @param board Pointer to the board to send the command to + * @param strand Strand to stop LED rotation + */ +METAWEAR_API void mbl_mw_neopixel_stop_rotation(const MblMwMetaWearBoard *board, uint8_t strand); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/peripheral_common.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/peripheral_common.h new file mode 100644 index 0000000..b8a7e16 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/peripheral_common.h @@ -0,0 +1,4 @@ +#include + +#include "metawear/core/metawearboard_fwd.h" +#include "metawear/platform/dllmarker.h" diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/btle_connection.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/btle_connection.h new file mode 100644 index 0000000..715fa71 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/btle_connection.h @@ -0,0 +1,92 @@ +/** + * @copyright MbientLab License + * @file btle_connection.h + * @brief Platform agnostic wrappers for Bluetooth Low Energy communication + */ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Write types for the GATT characteristic + */ +typedef enum { + MBL_MW_GATT_CHAR_WRITE_WITH_RESPONSE = 0, + MBL_MW_GATT_CHAR_WRITE_WITHOUT_RESPONSE +} MblMwGattCharWriteType; + +/** + * UUIDs identifying a gatt characteristic and its parent service + */ +typedef struct { + uint64_t service_uuid_high; ///< High 64 bits of the parent service uuid + uint64_t service_uuid_low; ///< Low 64 bits of the parent service uuid + uint64_t uuid_high; ///< High 64 bits of the characteristic uuid + uint64_t uuid_low; ///< Low 64 bits of the characteristic uuid +} MblMwGattChar; + +/** + * Definition for callback functions that accept a void pointer and byte array + * @param caller Object the callback is designated for + * @param start Pointer to the beginning of the byte array + * @param length Length of the byte array + */ +typedef int32_t(*MblMwFnIntVoidPtrArray)(const void* caller, const uint8_t* start, uint8_t length); +/** + * Definition for callback functions that accept a void pointer and an int32 + * @param caller Object the callback is designated for + * @param value Additional value passed to the function for context specific callbacks + */ +typedef void(*MblMwFnVoidVoidPtrInt)(const void* caller, int32_t value); + +/** + * Wrapper class containing functions for communicating with the MetaWear through a Bluetooth Low Energy connection. + */ +typedef struct { + /** + * Provides the calling function the ability to pass any context specific data required + */ + void *context; + /** + * Writes the characteristic and value to the device + * @param context Pointer to the context field + * @param caller Object using this function pointer + * @param characteristic Gatt characteristic to write + * @param value Value to write as a byte array + * @param length Length of the byte array + */ + void (*write_gatt_char)(void *context, const void* caller, MblMwGattCharWriteType writeType, const MblMwGattChar* characteristic, + const uint8_t* value, uint8_t length); + /** + * Reads the value of the characteristic from the device + * @param context Pointer to the context field + * @param caller Object using this function pointer + * @param characteristic Gatt characteristic to read + * @param handler Callback function to handle the received value + */ + void (*read_gatt_char)(void *context, const void* caller, const MblMwGattChar* characteristic, MblMwFnIntVoidPtrArray handler); + /** + * Enables notifications for characeristic changes + * @param context Pointer to the context field + * @param caller Object using this function pointer + * @param characteristic Characteristic to enable notifications for + * @param handler Callback function for handling characteristic notifications + * @param ready Callback function to handle when the enable notify task is completed + */ + void (*enable_notifications)(void *context, const void* caller, const MblMwGattChar* characteristic, MblMwFnIntVoidPtrArray handler, MblMwFnVoidVoidPtrInt ready); + /** + * Register a handler for disconnect events + * @param context Pointer to the context field + * @param caller Object using this function pointer + * @param handler Handler to respond to the disconnect event + */ + void (*on_disconnect)(void *context, const void* caller, MblMwFnVoidVoidPtrInt handler); +} MblMwBtleConnection; + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.cpp new file mode 100644 index 0000000..27d1f03 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.cpp @@ -0,0 +1,16 @@ +#include "async_creator.h" + +AsyncCreator::~AsyncCreator() { + if (timeout.use_count()) { + timeout->cancel(); + } +} + +void AsyncCreator::create_next(bool force) { + if (force && !pending_fns.empty()) { + pending_fns.pop(); + } + if ((force && !pending_fns.empty()) || (!force && pending_fns.size() == 1)) { + pending_fns.front()(); + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.h new file mode 100644 index 0000000..f876c45 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.h @@ -0,0 +1,16 @@ +#pragma once + +#include "metawear/platform/cpp/concurrent_queue.h" +#include "metawear/platform/cpp/task.h" + +#include +#include + +struct AsyncCreator { + virtual ~AsyncCreator(); + + ConcurrentQueue> pending_fns; + std::shared_ptr timeout; + + void create_next(bool force); +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/concurrent_queue.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/concurrent_queue.h new file mode 100644 index 0000000..e301f83 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/concurrent_queue.h @@ -0,0 +1,73 @@ +#include +#include + +template +class ConcurrentQueue { +public: + ConcurrentQueue() = default; + + void push(const T& item); + void push(T&& item); + + T& front(); + const T& front() const; + + void pop(); + void clear(); + + bool empty() const; + size_t size() const; +private: + mutable std::mutex queue_mutex; + std::queue elements; +}; + +template +void ConcurrentQueue::push(const T& item) { + std::lock_guard lock(queue_mutex); + elements.push(item); +} + +template +void ConcurrentQueue::push(T&& item) { + std::lock_guard lock(queue_mutex); + elements.push(item); +} + +template +T& ConcurrentQueue::front() { + std::lock_guard lock(queue_mutex); + return elements.front(); +} + +template +const T& ConcurrentQueue::front() const { + std::lock_guard lock(queue_mutex); + return elements.front(); +} + +template +void ConcurrentQueue::pop() { + std::lock_guard lock(queue_mutex); + elements.pop(); +} + +template +void ConcurrentQueue::clear() { + std::lock_guard lock(queue_mutex); + while(!elements.empty()) { + elements.pop(); + } +} + +template +bool ConcurrentQueue::empty() const { + std::lock_guard lock(queue_mutex); + return elements.empty(); +} + +template +size_t ConcurrentQueue::size() const { + std::lock_guard lock(queue_mutex); + return elements.size(); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/memory.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/memory.cpp new file mode 100644 index 0000000..1c8f585 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/memory.cpp @@ -0,0 +1,9 @@ +#include "metawear/platform/memory.h" + +#include + +using std::free; + +void mbl_mw_memory_free(void* ptr) { + free(ptr); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.cpp new file mode 100644 index 0000000..87e6d74 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.cpp @@ -0,0 +1,3 @@ +#include "task.h" + +Task::~Task() { } diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.h new file mode 100644 index 0000000..b216769 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.h @@ -0,0 +1,7 @@ +#pragma once + +class Task { +public: + virtual ~Task(); + virtual void cancel()= 0; +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.cpp new file mode 100644 index 0000000..7003e32 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.cpp @@ -0,0 +1,47 @@ +#include "threadpool.h" + +#include +#include +#include + +using std::atomic_bool; +using std::chrono::milliseconds; +using std::function; +using std::make_shared; +using std::shared_ptr; +using std::thread; + +const int64_t INDEFINITE_TIMEOUT= 0; + +class TaskImpl : public Task { +public: + TaskImpl(); + virtual ~TaskImpl(); + + virtual void cancel(); + + atomic_bool cancelled; +}; + +TaskImpl::TaskImpl() : cancelled(false) { } + +TaskImpl::~TaskImpl() { } + +void TaskImpl::cancel() { + cancelled= true; +} + +shared_ptr ThreadPool::schedule(function fn, int64_t delay) { + shared_ptr task(new TaskImpl()); + if (delay != INDEFINITE_TIMEOUT) { + thread th([=]() -> void { + std::this_thread::sleep_for(milliseconds(delay)); + if (!task->cancelled) { + fn(); + } + }); + th.detach(); + } + + return task; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.h new file mode 100644 index 0000000..f86546e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.h @@ -0,0 +1,12 @@ +#pragma once + +#include "task.h" + +#include +#include +#include + +class ThreadPool { +public: + static std::shared_ptr schedule(std::function fn, int64_t delay); +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/dllmarker.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/dllmarker.h new file mode 100644 index 0000000..caa36b9 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/dllmarker.h @@ -0,0 +1,37 @@ +/** + * @copyright MbientLab License + * @file dllmarker.h + * @brief Macros for identifying exported functions + */ +#pragma once + +#if defined _WIN32 || defined __CYGWIN__ +#define METAWEAR_HELPER_DLL_IMPORT __declspec(dllimport) +#define METAWEAR_HELPER_DLL_EXPORT __declspec(dllexport) +#define METAWEAR_HELPER_DLL_LOCAL +#else +#if __GNUC__ >= 4 +#define METAWEAR_HELPER_DLL_IMPORT __attribute__ ((visibility ("default"))) +#define METAWEAR_HELPER_DLL_EXPORT __attribute__ ((visibility ("default"))) +#define METAWEAR_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden"))) +#else +#define METAWEAR_HELPER_DLL_IMPORT +#define METAWEAR_HELPER_DLL_EXPORT +#define METAWEAR_HELPER_DLL_LOCAL +#endif +#endif + +#if defined _WINDLL || defined METAWEAR_DLL // defined if METAWEAR is compiled as a DLL +#ifdef METAWEAR_DLL_EXPORTS +/** Indicates the function should be exported to the symbol table */ +#define METAWEAR_API METAWEAR_HELPER_DLL_EXPORT +#else +#define METAWEAR_API METAWEAR_HELPER_DLL_IMPORT +#endif // METAWEAR_DLL_EXPORTS +/** Indicates the function is only to be used by the API */ +#define METAWEAR_LOCAL METAWEAR_HELPER_DLL_LOCAL +#else // METAWEAR_DLL is not defined: this means METAWEAR is a static lib. +#define METAWEAR_API +#define METAWEAR_LOCAL +#endif // METAWEAR_DLL + diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/memory.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/memory.h new file mode 100644 index 0000000..db10212 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/memory.h @@ -0,0 +1,22 @@ +/** + * @copyright MbientLab License + * @file memory.h + * @brief Memory management for memory allocated by the API + */ +#pragma once + +#include "dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Frees allocated memory + * @param ptr Pointer to the memory to free + */ +METAWEAR_API void mbl_mw_memory_free(void* ptr); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/accounter.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/accounter.h new file mode 100644 index 0000000..62191a1 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/accounter.h @@ -0,0 +1,38 @@ +/** + * @copyright MbientLab License + * @file accounter.h + * @brief Adds additional information to the payload to facilitate packet reconstruction + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Adds a system timer (timestamp) to the input signal. + * Not typically used. + * Adds additional information to the BTLE packet in the form of a counter + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_accounter_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created); + +/** + * Adds a simple counter (1,2,3...) to the input signal. + * Great to make sure the packets are coming in order. + * The count value is accessed through the MblMwData struct's extra field. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_accounter_create_count(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/accumulator.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/accumulator.h new file mode 100644 index 0000000..6e8d382 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/accumulator.h @@ -0,0 +1,45 @@ +/** + * @copyright MbientLab License + * @file accumulator.h + * @brief Tallies a running sum of the input + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Create an accumulator whose output is the same size as the input. + * Keeps a running sum of the input + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_accumulator_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created); +/** + * Create an accumulator with a specific output size. + * Keeps a running sum of the input and returns the output as the specified size + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param output_size Output size, between [1, 4] bytes + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_accumulator_create_size(MblMwDataSignal *source, uint8_t output_size, void *context, MblMwFnDataProcessor processor_created); +/** + * Overwrites the current accumulator value with a new value + * Can be used to reset the running sum + * @param accumulator Accumulator processor to modify + * @param new_running_sum New running sum of the accumulator + * @return MBL_MW_STATUS_OK if processor state was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if a non-accumulator + * was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_set_accumulator_state(MblMwDataProcessor *accumulator, float new_running_sum); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/average.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/average.h new file mode 100644 index 0000000..6b137a9 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/average.h @@ -0,0 +1,60 @@ +/** + * @copyright MbientLab License + * @file average.h + * @brief Computes a running average of the input + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @deprecated As of v0.10.0, use mbl_mw_dataprocessor_lowpass_create + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_average_create(MblMwDataSignal *source, uint8_t size, void *context, MblMwFnDataProcessor processor_created); +/** + * Create a high-pass filter + * Uses the averager to compute the difference of the current value from a running average of the previous (amount of) "size" samples. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param size Number of previous data samples to compare against, Recommended + * to be a power of 2 for faster computation. + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_highpass_create(MblMwDataSignal *source, uint8_t size, void *context, MblMwFnDataProcessor processor_created); +/** + * Create a low-pass filter + * Uses the averager to create a moving average. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param size Number of previous data samples to compare against, Recommended + * to be a power of 2 for faster computation. + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_lowpass_create(MblMwDataSignal *source, uint8_t size, void *context, MblMwFnDataProcessor processor_created); +/** + * Resets the running average (averager current value) + * @param average Average processor to reset + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-average processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_average_reset(MblMwDataProcessor *average); +/** + * Modifies the sample size of the average processor + * The sample size is the number of previous data samples to compare against + * Recommended to be a power of 2 for faster computation. + * @param average Average processor to modify + * @param size New sample size to use + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-average processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_average_modify_size(MblMwDataProcessor *average, uint8_t size); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/buffer.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/buffer.h new file mode 100644 index 0000000..36b60b8 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/buffer.h @@ -0,0 +1,27 @@ +/** + * @copyright MbientLab License + * @file buffer.h + * @brief Captures input data which can be retrieved at a later point in time + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Create a buffer processor. + * Stores one entry. Great for temporarily storing the output of other processors. + * Captures input data which can be retrieved at a later point in time + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_buffer_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/comparator.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/comparator.h new file mode 100644 index 0000000..6008a68 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/comparator.h @@ -0,0 +1,148 @@ +/** + * @copyright MbientLab License + * @file comparator.h + * @brief Only allows data through that satisfies a comparison operation + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Available operations for the processor + */ +typedef enum { + MBL_MW_COMPARATOR_OP_EQ = 0, ///< Equals to + MBL_MW_COMPARATOR_OP_NEQ, ///< Not equals to + MBL_MW_COMPARATOR_OP_LT, ///< Less than + MBL_MW_COMPARATOR_OP_LTE, ///< Less than or equals to + MBL_MW_COMPARATOR_OP_GT, ///< Greater than + MBL_MW_COMPARATOR_OP_GTE ///< Greater than or equals to +} MblMwComparatorOperation; + +/** + * Output modes for the comparator, only supported in firmware v1.2.3 and higher + */ +typedef enum { + MBL_MW_COMPARATOR_MODE_ABSOLUTE = 0, ///< Return the data as is + MBL_MW_COMPARATOR_MODE_REFERENCE, ///< Return the reference value for the satisfied comparison + MBL_MW_COMPARATOR_MODE_ZONE, ///< Return the position of the reference value satisfying the comparison, n + 1 for not satisfied + MBL_MW_COMPARATOR_MODE_BINARY ///< Return 1 if any reference values satisfy the comparison, 0 if none do +} MblMwComparatorMode; + +/** + * Create a comparator processor where signed/unsigned is inferred. + * Only allows data through that satisfies a comparison operation. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param op Comparison operation to execute (=, !=, <, >) + * @param reference Reference value to compare the input to + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_comparator_create(MblMwDataSignal *source, MblMwComparatorOperation op, float reference, + void *context, MblMwFnDataProcessor processor_created); +/** + * Create a comparator processor specifically for a signed comparison. + * Only allows data through that satisfies a comparison operation. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param op Comparison operation to execute (=, !=, <, >) + * @param reference Reference value to compare the input to + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_comparator_create_signed(MblMwDataSignal *source, MblMwComparatorOperation op, float reference, + void *context, MblMwFnDataProcessor processor_created); +/** + * Create a comparator processor specifically for an unsigned comparison. + * Only allows data through that satisfies a comparison operation. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param op Comparison operation to execute (=, !=, <, >) + * @param reference Reference value to compare the input to + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_comparator_create_unsigned(MblMwDataSignal *source, MblMwComparatorOperation op, float reference, + void *context, MblMwFnDataProcessor processor_created); +/** + * Modifies the comparator processor, changing the operation and reference value + * @param comparator Comparator processor to modify + * @param op New comparison operation (=, !=, <, >) + * @param reference New reference value + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-comparator processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_comparator_modify(MblMwDataProcessor *comparator, MblMwComparatorOperation op, float reference); +/** + * Modifies the comparator processor for a feedback or feedforward loop + * @param comparator Comparator processor to modify + * @param op New comparison operation (=, !=, <, >) + * @param reference_signal Data signal output to be used for the reference value + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-comparator processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_comparator_modify_signal(MblMwDataProcessor *comparator, MblMwComparatorOperation op, + MblMwDataSignal *reference_signal); +/** + * Create a multi-value comparator where a signed/unsigned comparison is inferred. + * This feature is only available on firmware v1.2.3 and later. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input + * @param op Comparison operation to execute (=, !=, <, >) + * @param mode Processor output mode + * @param references Array of reference values to compare against + * @param references_length Number of elements in the references array + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_multi_comparator_create(MblMwDataSignal* source, MblMwComparatorOperation op, MblMwComparatorMode mode, + float references[], uint8_t references_length, void *context, MblMwFnDataProcessor processor_created); +/** + * Create a multi-value comparator for signed comparisons. + * This feature is only available on firmware v1.2.3 and later. A pointer representing the + * processor will be passed back to the user via a callback function. + * @param source Data signal providing the input + * @param op Comparison operation to execute (=, !=, <, >) + * @param mode Processor output mode + * @param references Array of reference values to compare against + * @param references_length Number of elements in the references array + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_multi_comparator_create_signed(MblMwDataSignal* source, MblMwComparatorOperation op, MblMwComparatorMode mode, + float references[], uint8_t references_length, void *context, MblMwFnDataProcessor processor_created); +/** + * Create a multi-value comparator for unsigned comparisons. + * This feature is only available on firmware v1.2.3 and later. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input + * @param op Comparison operation to execute + * @param mode Processor output mode + * @param references Array of reference values to compare against + * @param references_length Number of elements in the references array + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_multi_comparator_create_unsigned(MblMwDataSignal* source, MblMwComparatorOperation op, MblMwComparatorMode mode, + float references[], uint8_t references_length, void *context, MblMwFnDataProcessor processor_created); +/** + * Modifies the multi-value comparator, changing the operation and reference values. + * This feature is only available on firmware v1.2.3 and later. + * @param comparator Comparator processor to modify + * @param op New comparison operation + * @param references Array of new reference values + * @param references_length Number of elements in the references array + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-comparator processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_multi_comparator_modify(MblMwDataProcessor *comparator, MblMwComparatorOperation op, float references[], + uint8_t references_length); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/counter.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/counter.h new file mode 100644 index 0000000..27d1963 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/counter.h @@ -0,0 +1,48 @@ +/** + * @copyright MbientLab License + * @file counter.h + * @brief Counts the number of times an event was fired + */ +#pragma once + +#include + +#include "dataprocessor_fwd.h" +#include "metawear/core/event_fwd.h" +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Create a counter with an output size of 1 byte. + * Counts the number of times an event was fired. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Event the processor is counting + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_counter_create(MblMwEvent *source, void *context, MblMwFnDataProcessor processor_created); +/** + * Create a counter with a specific output size. + * Counts the number of times an event was fired with a specific output size + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Event the processor is counting + * @param size Output size, between [1, 4] bytes + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_counter_create_size(MblMwEvent *source, uint8_t size, void *context, MblMwFnDataProcessor processor_created); +/** + * Overwrites the current count with a new value + * @param counter Counter processor to modify + * @param new_count New count value + * @return MBL_MW_STATUS_OK if processor state was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if a non-counter + * was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_counter_set_state(MblMwDataProcessor *counter, uint32_t new_count); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor.cpp new file mode 100644 index 0000000..4d02e5e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor.cpp @@ -0,0 +1,668 @@ +#include "dataprocessor_config.h" +#include "dataprocessor_private.h" +#include "dataprocessor_register.h" +#include "metawear/processor/dataprocessor.h" + +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include "metawear/platform/cpp/async_creator.h" +#include "metawear/platform/cpp/threadpool.h" + +#include "metawear/processor/comparator.h" +#include "metawear/processor/delta.h" +#include "metawear/processor/math.h" +#include "metawear/processor/pulse.h" +#include "metawear/processor/threshold.h" +#include "metawear/processor/time.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define GET_DATAPROCESSOR_STATE(board) static_pointer_cast(board->dp_state) + +const uint8_t NO_PARENT = -1; +const ResponseHeader DATAPROCESSOR_RESPONSE_HEADER(MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY)); + +unordered_map type_to_id= { + { DataProcessorType::ACCUMULATOR, 0x2 }, + { DataProcessorType::AVERAGE, 0x3 }, + { DataProcessorType::BUFFER, 0xf }, + { DataProcessorType::COMPARATOR, 0x6 }, + { DataProcessorType::COUNTER, 0x2 }, + { DataProcessorType::DELTA, 0xc }, + { DataProcessorType::MATH, 0x9 }, + { DataProcessorType::PASSTHROUGH, 0x1 }, + { DataProcessorType::PULSE, 0xb }, + { DataProcessorType::RMS, 0x7 }, + { DataProcessorType::RSS, 0x7 }, + { DataProcessorType::SAMPLE, 0xa }, + { DataProcessorType::THRESHOLD, 0xd }, + { DataProcessorType::TIME, 0x8 }, + { DataProcessorType::ACCOUNTER, 0x11 }, + { DataProcessorType::PACKER, 0x10 }, + { DataProcessorType::FUSER, 0x1b} +}; + +struct DataProcessorState : public AsyncCreator { + void *processor_context; + MblMwFnDataProcessor processor_callback; + MblMwDataProcessor* next_processor; + ProcessorEntriesHandler sync_handler; + stack chain; + uint8_t entry_id; +}; + + +static void create_processor_state_signal(MblMwDataProcessor* processor, DataInterpreter interpreter) { + ResponseHeader state_header(MBL_MW_MODULE_DATA_PROCESSOR, READ_REGISTER(ORDINAL(DataProcessorRegister::STATE))); + processor->state= new MblMwDataSignal(state_header, processor->owner, interpreter, processor->n_channels, + processor->channel_size, processor->is_signed, 0); +} + +MblMwDataProcessor* MblMwDataProcessor::transform(const MblMwDataSignal* input, uint8_t id, const void* config) { + auto processor = new MblMwDataProcessor(*input); + + switch(id) { + case 1: { + processor->type = DataProcessorType::PASSTHROUGH; + processor->config_size = sizeof(PassthroughConfig); + create_processor_state_signal(processor, DataInterpreter::UINT32); + break; + } + case 2: { + auto accumulator = (AccumulatorConfig*) config; + + processor->type = accumulator->mode == ACCUMULATOR_SUM ? DataProcessorType::ACCUMULATOR : DataProcessorType::COUNTER; + processor->config_size = sizeof(AccumulatorConfig); + + if (processor->type == DataProcessorType::COUNTER) { + processor->is_signed= 0; + processor->converter = FirmwareConverter::DEFAULT; + processor->interpreter = DataInterpreter::UINT32; + processor->set_channel_attr(1, accumulator->output + 1); + } else { + processor->set_channel_attr(input->n_channels, (accumulator->output + 1) / input->n_channels); + } + create_processor_state_signal(processor, processor->interpreter); + + break; + } + case 3: { + bool has_hpf = input->owner->module_info.at(MBL_MW_MODULE_DATA_PROCESSOR).revision >= HPF_REVISION; + + processor->type = DataProcessorType::AVERAGE; + processor->config_size = sizeof(AverageConfig) - (has_hpf ? 0 : 1); + break; + } + case 6: { + if (!(input->owner->firmware_revision < MULTI_COMPARE)) { + auto compare = (MultiComparatorConfig*) config; + + processor->config_size = sizeof(MultiComparatorConfig); + if (compare->mode == MBL_MW_COMPARATOR_MODE_ZONE || compare->mode == MBL_MW_COMPARATOR_MODE_BINARY) { + processor->interpreter= DataInterpreter::UINT32; + processor->converter= FirmwareConverter::DEFAULT; + processor->is_signed= 0; + processor->set_channel_attr(1, 1); + } + } else { + auto compare = (ComparatorConfig*) config; + processor->config_size = sizeof(ComparatorConfig); + processor->is_signed = compare->is_signed; + } + processor->type = DataProcessorType::COMPARATOR; + break; + } + case 7: { + auto combiner = (CombinerConfig*) config; + + processor->config_size = sizeof(CombinerConfig); + processor->is_signed= 0; + processor->offset= 0; + processor->set_channel_attr(1, input->channel_size); + + switch (input->interpreter) { + case DataInterpreter::BOSCH_ACCELERATION: + processor->interpreter= DataInterpreter::BOSCH_ACCELERATION_UNSIGNED_SINGLE_AXIS; + break; + case DataInterpreter::MMA8452Q_ACCELERATION: + processor->interpreter = DataInterpreter::MMA8452Q_ACCELERATION_UNSIGNED_SINGLE_AXIS; + break; + case DataInterpreter::BOSCH_ROTATION: + processor->interpreter = DataInterpreter::BOSCH_ROTATION_UNSIGNED_SINGLE_AXIS; + break; + case DataInterpreter::BMM150_B_FIELD: + processor->interpreter = DataInterpreter::BMM150_B_FIELD_UNSIGNED_SINGLE_AXIS; + break; + case DataInterpreter::TCS34725_COLOR_ADC: + processor->interpreter = DataInterpreter::UINT32; + break; + default: + break; + } + + processor->type = combiner->mode == COMBINER_RMS ? DataProcessorType::RMS : DataProcessorType::RSS; + break; + } + case 8: { + auto time = (TimeDelayConfig*) config; + + processor->config_size = sizeof(TimeDelayConfig); + if (time->mode == MBL_MW_TIME_DIFFERENTIAL) { + processor->make_signed(); + } + + processor->type = DataProcessorType::TIME; + break; + } + case 9: { + auto math = (MathConfig*) config; + + processor->config_size = sizeof(MathConfig) - (input->owner->firmware_revision < MULTI_CHANNEL_MATH ? 1 : 0); + + switch (math->operation) { + // Use the is_signed value to determine if data will be signed/unsigned + case MBL_MW_MATH_OP_ADD: + case MBL_MW_MATH_OP_MULTIPLY: + case MBL_MW_MATH_OP_DIVIDE: + case MBL_MW_MATH_OP_MODULUS: + if (math->is_signed) { + processor->make_signed(); + } else { + processor->make_unsigned(); + } + break; + // data always signed for subtract + case MBL_MW_MATH_OP_SUBTRACT: + processor->make_signed(); + break; + // data always unsigned for sqrt & abs + case MBL_MW_MATH_OP_SQRT: + case MBL_MW_MATH_OP_ABS_VALUE: + processor->make_unsigned(); + break; + default: + break; + } + + switch (math->operation) { + case MBL_MW_MATH_OP_EXPONENT: + case MBL_MW_MATH_OP_SQRT: + case MBL_MW_MATH_OP_LSHIFT: + case MBL_MW_MATH_OP_RSHIFT: + if (processor->interpreter != DataInterpreter::INT32 && processor->interpreter != DataInterpreter::UINT32) { + processor->interpreter = DataInterpreter::BYTE_ARRAY; + } + processor->converter = FirmwareConverter::DEFAULT; + break; + case MBL_MW_MATH_OP_CONSTANT: + processor->interpreter = DataInterpreter::INT32; + processor->converter = FirmwareConverter::DEFAULT; + default: + break; + } + + uint32_t* rhs = (uint32_t*) &(math->rhs); + switch (math->operation) { + case MBL_MW_MATH_OP_RSHIFT: + processor->channel_size= max(1, (int) (input->channel_size - (*rhs / 8))); + break; + case MBL_MW_MATH_OP_LSHIFT: + processor->channel_size= min(4, input->channel_size + (uint8_t) ceil(*rhs / 8)); + break; + default: + processor->channel_size= 4; + } + + processor->type = DataProcessorType::MATH; + break; + } + case 0xa: { + processor->type = DataProcessorType::SAMPLE; + processor->config_size = sizeof(SampleDelayConfig); + break; + } + case 0xb: { + auto pulse = (PulseDetectorConfig*) config; + + processor->config_size = sizeof(PulseDetectorConfig); + + switch (pulse->output_mode) { + case MBL_MW_PULSE_OUTPUT_WIDTH: + processor->set_channel_attr(1, 2); + processor->interpreter = DataInterpreter::UINT32; + processor->converter = FirmwareConverter::DEFAULT; + break; + case MBL_MW_PULSE_OUTPUT_AREA: + processor->set_channel_attr(1, 4); + break; + case MBL_MW_PULSE_OUTPUT_ON_DETECTION: + processor->is_signed = 0; + processor->set_channel_attr(1, 1); + processor->interpreter = DataInterpreter::UINT32; + processor->converter = FirmwareConverter::DEFAULT; + break; + default: + break; + } + + processor->type = DataProcessorType::PULSE; + break; + } + case 0xc: { + auto delta = (DeltaConfig*) config; + + processor->config_size = sizeof(DeltaConfig); + switch (delta->mode) { + case MBL_MW_DELTA_MODE_DIFFERENTIAL: + processor->make_signed(); + break; + case MBL_MW_DELTA_MODE_BINARY: + processor->is_signed = 1; + processor->interpreter = DataInterpreter::INT32; + processor->set_channel_attr(1, 1); + processor->converter = FirmwareConverter::DEFAULT; + break; + default: + break; + } + processor->type = DataProcessorType::DELTA; + + create_processor_state_signal(processor, processor->interpreter); + + break; + } + case 0xd: { + auto threshold = (ThresholdConfig*) config; + + processor->config_size = sizeof(ThresholdConfig); + if (threshold->mode == MBL_MW_THRESHOLD_MODE_BINARY) { + processor->is_signed = 1; + processor->interpreter = DataInterpreter::INT32; + processor->set_channel_attr(1, 1); + processor->converter = FirmwareConverter::DEFAULT; + } + + processor->type = DataProcessorType::THRESHOLD; + break; + } + case 0xf: { + processor->type = DataProcessorType::BUFFER; + processor->config_size = sizeof(BufferConfig); + create_processor_state_signal(processor, processor->interpreter); + break; + } + case 0x10: { + processor->type = DataProcessorType::PACKER; + processor->config_size = sizeof(PackerConfig); + break; + } + case 0x11: { + auto accounter = (AccounterConfig*) config; + processor->config_size = sizeof(AccounterConfig); + processor->channel_size+= accounter->length + 1; + processor->type = DataProcessorType::ACCOUNTER; + break; + } + case 0x1b: { + auto fuse = (FuseConfig*) config; + processor->config_size = sizeof(FuseConfig); + processor->channel_size = input->length(); + processor->n_channels = 1; + processor->type = DataProcessorType::FUSER; + processor->interpreter = DataInterpreter::FUSED_DATA; + processor->converter = FirmwareConverter::DEFAULT; + + for(uint8_t i = 0; i < fuse->count; i++) { + auto value = lookup_processor(input->owner, fuse->references[i]); + processor->channel_size+= value->length(); + } + + break; + } + } + + processor->config = malloc(processor->config_size); + memcpy(processor->config, config, processor->config_size); + return processor; +} + +MblMwDataProcessor* MblMwDataProcessor::transform(const MblMwDataSignal* input, const std::vector& config) { + return MblMwDataProcessor::transform(input, config[0], config.data() + 1); +} + +MblMwDataProcessor::MblMwDataProcessor(uint8_t** state_stream, MblMwMetaWearBoard *owner) : MblMwDataSignal(state_stream, owner) { + parent_id = **state_stream; + + config_size = *(++(*state_stream)); + config = malloc(config_size); + memcpy(config, ++(*state_stream), config_size); + + *state_stream += config_size; + uint8_t n_consumers = **state_stream; + for (uint8_t i = 0; i < n_consumers; i++) { + consumers.push_back(*(++(*state_stream))); + } + + type = static_cast(*(++(*state_stream))); + + (*state_stream)++; +} + +MblMwDataProcessor::MblMwDataProcessor(const MblMwDataSignal& signal) : MblMwDataSignal(signal.header, signal.owner, + signal.interpreter, signal.converter, signal.n_channels, signal.channel_size, signal.is_signed, signal.offset), + parent_id(NO_PARENT), state(nullptr), input(&signal), config(nullptr) { + offset = 0; + header.module_id = MBL_MW_MODULE_DATA_PROCESSOR; + header.register_id = ORDINAL(DataProcessorRegister::NOTIFY); + + if (const MblMwDataProcessor* source= dynamic_cast(&signal)) { + parent_id= source->header.data_id; + } +} + +MblMwDataProcessor::~MblMwDataProcessor() { + free(config); + config= nullptr; + + if (remove) { + uint8_t command[3]= { MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::REMOVE), header.data_id }; + send_command(owner, command, sizeof(command)); + } +} + +void MblMwDataProcessor::subscribe() { + uint8_t enable_command[4] = { MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY_ENABLE), header.data_id, 1 }; + send_command(owner, enable_command, sizeof(enable_command)); + + uint8_t enable_notify[3] = { MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY), 1 }; + send_command(owner, enable_notify, sizeof(enable_notify)); +} + +void MblMwDataProcessor::unsubscribe() { + uint8_t disable_command[4] = { MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY_ENABLE), header.data_id, 0 }; + send_command(owner, disable_command, sizeof(disable_command)); +} + +MblMwDataProcessor* MblMwDataProcessor::parent() const { + ResponseHeader parent_header(MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY), parent_id); + return owner->module_events.count(parent_header) ? + dynamic_cast(owner->module_events.at(parent_header)) : + nullptr; +} + +void MblMwDataProcessor::serialize(vector& state) const { + MblMwDataSignal::serialize(state); + + state.push_back(parent_id); + + state.push_back((uint8_t) config_size); + state.insert(state.end(), (uint8_t*) config, ((uint8_t*) config) + config_size); + + state.push_back((uint8_t) consumers.size()); + state.insert(state.end(), consumers.begin(), consumers.end()); + + state.push_back(static_cast(type)); +} + +static const char* type_to_uri(DataProcessorType type, void* config) { + switch(type) { + case DataProcessorType::ACCUMULATOR: + return "accumulate"; + case DataProcessorType::AVERAGE: + return ((AverageConfig*) config)->mode == USE_HPF ? "high-pass" : "low-pass"; + case DataProcessorType::BUFFER: + return "buffer"; + case DataProcessorType::COMPARATOR: + return "comparison"; + case DataProcessorType::COUNTER: + return "count"; + case DataProcessorType::DELTA: + return "differential"; + case DataProcessorType::MATH: + return "math"; + case DataProcessorType::PASSTHROUGH: + return "passthrough"; + case DataProcessorType::PULSE: + return "pulse"; + case DataProcessorType::RMS: + return "rms"; + case DataProcessorType::RSS: + return "rss"; + case DataProcessorType::SAMPLE: + return "delay"; + case DataProcessorType::THRESHOLD: + return "threshold"; + case DataProcessorType::TIME: + return "time"; + case DataProcessorType::ACCOUNTER: + return "account"; + case DataProcessorType::PACKER: + return "packer"; + case DataProcessorType::FUSER: + return "fuser"; + default: + return nullptr; + } +} + +void MblMwDataProcessor::create_uri(std::stringstream& uri) const { + uri << type_to_uri(type, config) << "?id=" << (int) header.data_id; +} + +void create_dataprocessor_state_uri(const MblMwDataSignal* signal, stringstream& uri) { + ResponseHeader header(MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY), signal->header.data_id); + auto processor = dynamic_cast(signal->owner->module_events.at(header)); + + uri << type_to_uri(processor->type, processor->config) << "-state?id=" << (int) processor->header.data_id; +} + +static int32_t dataprocessor_created(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state = GET_DATAPROCESSOR_STATE(board); + + state->timeout->cancel(); + state->next_processor->header.data_id = response[2]; + + auto proc_parent = state->next_processor->parent(); + if (proc_parent != nullptr) { + proc_parent->consumers.push_back(response[2]); + } + + if (state->next_processor->state != nullptr) { + state->next_processor->state->header.data_id = response[2]; + state->next_processor->owner->module_events[state->next_processor->state->header] = state->next_processor->state; + state->next_processor->state = nullptr; + } + + state->next_processor->owner->module_events.emplace(state->next_processor->header, state->next_processor); + state->processor_callback(state->processor_context, state->next_processor); + state->create_next(true); + + return MBL_MW_STATUS_OK; +} + +static int32_t dataprocessor_config_received(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state = GET_DATAPROCESSOR_STATE(board); + state->timeout->cancel(); + + ProcessorEntry entry = { + state->entry_id, + static_cast(response[5] & 0x1f), + static_cast(((response[5] >> 5) & 0x7) + 1), + ResponseHeader(response[2], response[3], response[4]) + }; + entry.config.insert(entry.config.end(), response + 6, response + len); + + state->chain.push(entry); + + if (response[2] == MBL_MW_MODULE_DATA_PROCESSOR && response[3] == ORDINAL(DataProcessorRegister::NOTIFY)) { + state->entry_id = response[4]; + state->pending_fns.push([=](void) -> void { + state->timeout= ThreadPool::schedule([state, board](void) -> void { + board->anon_signals_created(board->anon_signals_context, board, nullptr, MBL_MW_STATUS_ERROR_TIMEOUT); + state->create_next(true); + }, board->time_per_response); + + uint8_t command[3] = { MBL_MW_MODULE_DATA_PROCESSOR, READ_REGISTER(ORDINAL(DataProcessorRegister::ADD)), response[4] }; + SEND_COMMAND; + }); + } else { + state->sync_handler(board, state->chain); + } + state->create_next(true); + + return MBL_MW_STATUS_OK; +} + +void init_dataprocessor_module(MblMwMetaWearBoard* board) { + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY)), + forward_as_tuple(response_handler_data_with_id)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::ADD)), + forward_as_tuple(dataprocessor_created)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_DATA_PROCESSOR, READ_REGISTER(ORDINAL(DataProcessorRegister::ADD))), + forward_as_tuple(dataprocessor_config_received)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_DATA_PROCESSOR, READ_REGISTER(ORDINAL(DataProcessorRegister::STATE))), + forward_as_tuple(response_handler_data_with_id)); + + if (!board->dp_state) { + board->dp_state = make_shared(); + } +} + +void free_dataprocessor_module(void* state) { + delete (DataProcessorState*) state; +} + +void disconnect_dataprocessor(MblMwMetaWearBoard* board) { + auto state = GET_DATAPROCESSOR_STATE(board); + if (state != nullptr) { + state->pending_fns.clear(); + } +} + +MblMwDataSignal* mbl_mw_dataprocessor_get_state_data_signal(const MblMwDataProcessor* processor) { + ResponseHeader state_header(MBL_MW_MODULE_DATA_PROCESSOR, READ_REGISTER(ORDINAL(DataProcessorRegister::STATE)), processor->header.data_id); + GET_DATA_SIGNAL_BOARD(processor->owner, state_header); +} + +void mbl_mw_dataprocessor_remove(MblMwDataProcessor *processor) { + if (processor->parent_id != NO_PARENT) { + auto parent_consumers= &processor->parent()->consumers; + parent_consumers->erase(find(parent_consumers->begin(), parent_consumers->end(), processor->header.data_id)); + } + + function remove_inner= [&remove_inner](MblMwDataProcessor *current) -> void { + for(auto it: current->consumers) { + ResponseHeader consumer_header(MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY), it); + remove_inner(dynamic_cast(current->owner->module_events.at(consumer_header))); + } + + auto state_signal = mbl_mw_dataprocessor_get_state_data_signal(current); + if (state_signal != nullptr) { + state_signal->header.disable_silent(); + current->owner->module_events.erase(state_signal->header); + delete state_signal; + } + + current->owner->module_events.erase(current->header); + delete current; + }; + + remove_inner(processor); +} + +uint8_t mbl_mw_dataprocessor_get_id(const MblMwDataProcessor* processor) { + return processor->header.data_id; +} + +MblMwDataProcessor* mbl_mw_dataprocessor_lookup_id(const MblMwMetaWearBoard* board, uint8_t id) { + ResponseHeader map_key(MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY), id); + return dynamic_cast(board->module_events.at(map_key)); +} + +void create_processor(MblMwDataSignal* source, MblMwDataProcessor* processor, void *context, MblMwFnDataProcessor processor_created) { + auto state = GET_DATAPROCESSOR_STATE(processor->owner); + state->pending_fns.push([state, processor, context, processor_created, source](void) -> void { + state->next_processor= processor; + state->processor_context= context; + state->processor_callback= processor_created; + + vector command = { MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::ADD), source->header.module_id, + source->header.register_id, source->header.data_id, source->get_data_ubyte(), type_to_id.at(processor->type) }; + command.insert(command.end(), (uint8_t*) processor->config, ((uint8_t*) processor->config) + processor->config_size); + + state->timeout= ThreadPool::schedule([state](void) -> void { + if (state->next_processor->state != nullptr) { + delete state->next_processor->state; + } + state->next_processor->remove = false; + delete state->next_processor; + state->processor_callback(state->processor_context, nullptr); + + state->create_next(true); + }, source->owner->time_per_response); + send_command(source->owner, command.data(), (uint8_t) command.size()); + }); + state->create_next(false); +} + +void set_processor_state(MblMwDataProcessor *processor, void* new_state, uint8_t size) { + vector command = { MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::STATE), processor->header.data_id }; + if (new_state != nullptr) { + command.insert(command.end(), (uint8_t*) new_state, ((uint8_t*) new_state) + size); + } + send_command(processor->owner, command.data(), (uint8_t) command.size()); +} + +void modify_processor_configuration(MblMwDataProcessor *processor, uint8_t size) { + vector command = { MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::PARAMETER), processor->header.data_id, + type_to_id.at(processor->type)}; + command.insert(command.end(), (uint8_t*) processor->config, ((uint8_t*) processor->config) + size); + send_command(processor->owner, command.data(), (uint8_t) command.size()); +} + +void sync_processor_chain(MblMwMetaWearBoard* board, uint8_t id, ProcessorEntriesHandler handler) { + auto state = GET_DATAPROCESSOR_STATE(board); + + while(!state->chain.empty()) { + state->chain.pop(); + } + state->entry_id = id; + state->sync_handler = handler; + + state->pending_fns.push([=](void) -> void { + state->timeout= ThreadPool::schedule([state, board](void) -> void { + board->anon_signals_created(board->anon_signals_context, board, nullptr, MBL_MW_STATUS_ERROR_TIMEOUT); + state->create_next(true); + }, board->time_per_response); + + uint8_t command[3] = { MBL_MW_MODULE_DATA_PROCESSOR, READ_REGISTER(ORDINAL(DataProcessorRegister::ADD)), id }; + SEND_COMMAND; + }); + state->create_next(false); +} + +MblMwDataProcessor* lookup_processor(const MblMwMetaWearBoard* board, uint8_t id) { + ResponseHeader key = {MBL_MW_MODULE_DATA_PROCESSOR, ORDINAL(DataProcessorRegister::NOTIFY), id}; + return dynamic_cast(board->module_events.at(key)); +} + +namespace std { + +size_t hash::operator()(const DataProcessorType& key) const { + return static_cast(key); +} + +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.cpp new file mode 100644 index 0000000..6a8e618 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.cpp @@ -0,0 +1,766 @@ +#include "dataprocessor_config.h" +#include "dataprocessor_private.h" + +#include "metawear/core/status.h" +#include "metawear/core/cpp/constant.h" +#include "metawear/core/cpp/metawearboard_def.h" + +#include "metawear/processor/accounter.h" +#include "metawear/processor/accumulator.h" +#include "metawear/processor/average.h" +#include "metawear/processor/buffer.h" +#include "metawear/processor/comparator.h" +#include "metawear/processor/counter.h" +#include "metawear/processor/delta.h" +#include "metawear/processor/math.h" +#include "metawear/processor/packer.h" +#include "metawear/processor/passthrough.h" +#include "metawear/processor/pulse.h" +#include "metawear/processor/rms.h" +#include "metawear/processor/rss.h" +#include "metawear/processor/sample.h" +#include "metawear/processor/threshold.h" +#include "metawear/processor/time.h" +#include "metawear/processor/fuser.h" + +#include +#include +#include +#include + +using namespace std; + +uint8_t get_accounter_type(const MblMwDataProcessor* source) { + return ((AccounterConfig*)source->config)->mode; +} + +uint8_t get_accounter_length(const MblMwDataProcessor* source) { + return ((AccounterConfig*)source->config)->length + 1; +} + +uint8_t get_accounter_prescale(const MblMwDataProcessor* source) { + return ((AccounterConfig*)source->config)->prescale + 1; +} + +static int32_t create_accounter_processor(MblMwDataSignal *source, uint8_t mode, uint8_t length, void *context, MblMwFnDataProcessor processor_created) { + AccounterConfig config; + memset(&config, 0, sizeof(AccounterConfig)); + config.mode = mode; + config.length = (length - 1); + config.prescale = 0x3; // This is what the logger uses, so we follow suit for now + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::ACCOUNTER), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_accounter_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created) { + const uint8_t length = 4; // Fix to 4 byte length for now + return source->length() + length + 3 >= BLE_PACKET_SIZE ? MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR : + create_accounter_processor(source, ACCOUNTER_TIME, length, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_accounter_create_count(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created) { + int8_t length = min(4, BLE_PACKET_SIZE - 3 - source->length()); + return length < 0 ? MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR : + create_accounter_processor(source, ACCOUNTER_COUNT, (uint8_t) length, context, processor_created); +} + +static int32_t create_accumulator_processor(MblMwDataSignal *source, uint8_t n_channels, uint8_t channel_size, + DataProcessorType accum_type, void *context, MblMwFnDataProcessor processor_created) { + if (source->length() > PROCESSOR_MAX_LENGTH) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + AccumulatorConfig config; + memset(&config, 0, sizeof(AccumulatorConfig)); + config.output = (n_channels * channel_size) - 1; + config.input= (source->length() - 1); + config.mode= accum_type == DataProcessorType::ACCUMULATOR ? ACCUMULATOR_SUM : ACCUMULATOR_COUNT; + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(accum_type), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_accumulator_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created) { + return create_accumulator_processor(source, source->n_channels, source->channel_size, DataProcessorType::ACCUMULATOR, + context, processor_created); +} +int32_t mbl_mw_dataprocessor_accumulator_create_size(MblMwDataSignal *source, uint8_t output_size, + void *context, MblMwFnDataProcessor processor_created) { + return create_accumulator_processor(source, source->n_channels, output_size, DataProcessorType::ACCUMULATOR, context, processor_created); +} +int32_t mbl_mw_dataprocessor_set_accumulator_state(MblMwDataProcessor *accumulator, float new_running_sum) { + if (accumulator->type == DataProcessorType::ACCUMULATOR) { + uint32_t scaled_sum= (uint32_t) number_to_firmware_converters.at(accumulator->converter)(accumulator, new_running_sum); + set_processor_state(accumulator, &scaled_sum, sizeof(scaled_sum)); + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_counter_create(MblMwEvent *source, void *context, MblMwFnDataProcessor processor_created) { + return mbl_mw_dataprocessor_counter_create_size(source, 1, context, processor_created); +} +int32_t mbl_mw_dataprocessor_counter_create_size(MblMwEvent *source, uint8_t size, void *context, MblMwFnDataProcessor processor_created) { + if (MblMwDataSignal* src_signal= dynamic_cast(source)) { + return create_accumulator_processor(src_signal, 1, size, DataProcessorType::COUNTER, context, processor_created); + } + + MblMwDataSignal event_signal(*source); + return create_accumulator_processor(&event_signal, 1, 1, DataProcessorType::COUNTER, context, processor_created); +} +int32_t mbl_mw_dataprocessor_counter_set_state(MblMwDataProcessor *counter, uint32_t new_count) { + if (counter->type == DataProcessorType::COUNTER) { + set_processor_state(counter, &new_count, sizeof(new_count)); + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +static int32_t apply_average(MblMwDataSignal *source, bool use_hpf, uint8_t size, void *context, MblMwFnDataProcessor processor_created) { + bool has_hpf = source->owner->module_info.at(MBL_MW_MODULE_DATA_PROCESSOR).revision >= HPF_REVISION; + + if (!has_hpf && source->length() > PROCESSOR_MAX_LENGTH) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + AverageConfig config; + memset(&config, 0, sizeof(AverageConfig)); + config.output= source->length() - 1; + config.input= source->length() - 1; + config.size= size; + config.count = source->n_channels - 1; + + if (has_hpf && use_hpf) { + config.mode = USE_HPF; + } + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::AVERAGE), &config), context, processor_created); + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_average_create(MblMwDataSignal *source, uint8_t size, void *context, MblMwFnDataProcessor processor_created) { + return mbl_mw_dataprocessor_lowpass_create(source, size, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_highpass_create(MblMwDataSignal *source, uint8_t size, void *context, MblMwFnDataProcessor processor_created) { + return apply_average(source, true, size, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_lowpass_create(MblMwDataSignal *source, uint8_t size, void *context, MblMwFnDataProcessor processor_created) { + return apply_average(source, false, size, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_average_reset(MblMwDataProcessor *average) { + if (average->type == DataProcessorType::AVERAGE) { + set_processor_state(average, nullptr, 0); + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_average_modify_size(MblMwDataProcessor *average, uint8_t size) { + if (average->type == DataProcessorType::AVERAGE) { + bool has_hpf = average->owner->module_info.at(MBL_MW_MODULE_DATA_PROCESSOR).revision >= HPF_REVISION; + ((AverageConfig*) average->config)->size= size; + modify_processor_configuration(average, sizeof(AverageConfig) - (has_hpf ? 0 : 1)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +const Version BUFFER_PROCESSOR(1, 1, 0); + +int32_t mbl_mw_dataprocessor_buffer_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created) { + if (source->owner->firmware_revision < BUFFER_PROCESSOR) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + BufferConfig config; + memset(&config, 0, sizeof(BufferConfig)); + config.length= source->length() - 1; + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::BUFFER), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +static inline int32_t create_combiner(MblMwDataSignal *source, DataProcessorType combiner_type, + void *context, MblMwFnDataProcessor processor_created) { + if (source->n_channels <= 1) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + CombinerConfig config; + config.output= source->channel_size - 1; + config.input= source->channel_size - 1; + config.count= source->n_channels - 1; + config.is_signed= source->is_signed; + config.mode= combiner_type == DataProcessorType::RMS ? COMBINER_RMS : COMBINER_RSS; + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(combiner_type), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_rms_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created) { + return create_combiner(source, DataProcessorType::RMS, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_rss_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created) { + return create_combiner(source, DataProcessorType::RSS, context, processor_created); +} + +#define SCALE_MULTI_COMP_REFERENCE(cfg, signal, type) for(uint8_t i= 0; i < references_length; i++) {\ + type scaled= (type) number_to_firmware_converters.at(signal->converter)(signal, references[i]);\ + memcpy(cfg.references + offset, &scaled, sizeof(type));\ + offset+= sizeof(type);\ +}\ + +static int32_t create_multi_comparator(MblMwDataSignal* source, MblMwComparatorOperation op, MblMwComparatorMode mode, float references[], + uint8_t references_length, uint8_t is_signed, void *context, MblMwFnDataProcessor processor_created) { + if (source->owner->firmware_revision < MULTI_COMPARE || source->length() > PROCESSOR_MAX_LENGTH) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + MultiComparatorConfig config; + config.is_signed= is_signed; + config.length= source->length() - 1; + config.operation= op; + config.mode= mode; + + uint8_t offset= 0; + switch(source->length()) { + case 1: + SCALE_MULTI_COMP_REFERENCE(config, source, int8_t); + break; + case 2: + SCALE_MULTI_COMP_REFERENCE(config, source, int16_t); + break; + case 4: + SCALE_MULTI_COMP_REFERENCE(config, source, int32_t); + break; + } + + auto new_processor = MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::COMPARATOR), &config); + new_processor->config_size = 1 + offset; + create_processor(source, new_processor, context, processor_created); + + return MBL_MW_STATUS_OK; +} + +static inline int32_t create_comprator(MblMwDataSignal *source, MblMwComparatorOperation op, float reference, uint8_t is_signed, + void *context, MblMwFnDataProcessor processor_created) { + if (source->length() > PROCESSOR_MAX_LENGTH) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + if (source->owner->firmware_revision < MULTI_COMPARE) { + ComparatorConfig config; + *((uint8_t*) &config + 2)= 0; + config.is_signed= is_signed; + config.operation= op; + + int32_t scaled_reference= (int32_t) number_to_firmware_converters.at(source->converter)(source, reference); + memcpy(((uint8_t*)(&config)) + 3, &scaled_reference, sizeof(scaled_reference)); + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::COMPARATOR), &config), context, processor_created); + return MBL_MW_STATUS_OK; + } else { + return create_multi_comparator(source, op, MBL_MW_COMPARATOR_MODE_ABSOLUTE, &reference, 1, is_signed, context, processor_created); + } +} + +int32_t mbl_mw_dataprocessor_comparator_create(MblMwDataSignal *source, MblMwComparatorOperation op, float reference, + void *context, MblMwFnDataProcessor processor_created) { + return create_comprator(source, op, reference, source->is_signed ? 1 : 0, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_comparator_create_signed(MblMwDataSignal *source, MblMwComparatorOperation op, float reference, + void *context, MblMwFnDataProcessor processor_created) { + return create_comprator(source, op, reference, 1, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_comparator_create_unsigned(MblMwDataSignal *source, MblMwComparatorOperation op, float reference, + void *context, MblMwFnDataProcessor processor_created) { + return create_comprator(source, op, reference, 0, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_comparator_modify(MblMwDataProcessor *comparator, MblMwComparatorOperation op, float reference) { + if (!(comparator->owner->firmware_revision < MULTI_COMPARE)) { + return mbl_mw_dataprocessor_multi_comparator_modify(comparator, op, &reference, 1); + } + + if (comparator->type == DataProcessorType::COMPARATOR) { + int32_t scaled_reference= (int32_t) number_to_firmware_converters.at(comparator->converter)(comparator, reference); + memcpy(((uint8_t*)(comparator->config)) + 3, &scaled_reference, sizeof(scaled_reference)); + ((ComparatorConfig*) comparator->config)->operation= op; + + modify_processor_configuration(comparator, sizeof(ComparatorConfig)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_comparator_modify_signal(MblMwDataProcessor *comparator, MblMwComparatorOperation op, MblMwDataSignal *reference_signal) { + if (comparator->type == DataProcessorType::COMPARATOR) { + if (comparator->owner->firmware_revision < MULTI_COMPARE) { + ComparatorConfig* current_config= (ComparatorConfig*) comparator->config; + + memset(((uint8_t*)(current_config)) + 3, 0, sizeof(current_config->reference)); + current_config->operation= op; + + EventDataParameter signal_data_token= {reference_signal->length(), reference_signal->offset, 5}; + + set_data_token(comparator->owner, &signal_data_token); + modify_processor_configuration(comparator, sizeof(ComparatorConfig)); + clear_data_token(comparator->owner); + + return MBL_MW_STATUS_OK; + } else { + MultiComparatorConfig* config= (MultiComparatorConfig*) malloc(sizeof(MultiComparatorConfig)); + + *((uint8_t*) config)= *((uint8_t*) comparator->config); + config->operation= op; + + uint8_t real_length= min((uint8_t) (config->length + 1), reference_signal->length()); + free(comparator->config); + comparator->config= config; + comparator->config_size= 1 + real_length; + memset(config->references, 0, real_length); + + EventDataParameter signal_data_token= {real_length, reference_signal->offset, 3}; + + set_data_token(comparator->owner, &signal_data_token); + modify_processor_configuration(comparator, comparator->config_size); + clear_data_token(comparator->owner); + + return MBL_MW_STATUS_OK; + } + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_multi_comparator_create(MblMwDataSignal* source, MblMwComparatorOperation op, MblMwComparatorMode mode, float references[], + uint8_t references_length, void *context, MblMwFnDataProcessor processor_created) { + return create_multi_comparator(source, op, mode, references, references_length, source->is_signed ? 1 : 0, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_multi_comparator_create_signed(MblMwDataSignal* source, MblMwComparatorOperation op, MblMwComparatorMode mode, + float references[], uint8_t references_length, void *context, MblMwFnDataProcessor processor_created) { + return create_multi_comparator(source, op, mode, references, references_length, 1, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_multi_comparator_create_unsigned(MblMwDataSignal* source, MblMwComparatorOperation op, MblMwComparatorMode mode, + float references[], uint8_t references_length, void *context, MblMwFnDataProcessor processor_created) { + return create_multi_comparator(source, op, mode, references, references_length, 0, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_multi_comparator_modify(MblMwDataProcessor *comparator, MblMwComparatorOperation op, float references[], + uint8_t references_length) { + if (comparator->type == DataProcessorType::COMPARATOR) { + MultiComparatorConfig* config= (MultiComparatorConfig*) malloc(sizeof(MultiComparatorConfig)); + + *((uint8_t*) config)= *((uint8_t*) comparator->config); + config->operation= op; + + uint8_t offset= 0; + switch(config->length) { + case 0: + SCALE_MULTI_COMP_REFERENCE((*config), comparator, int8_t); + break; + case 1: + SCALE_MULTI_COMP_REFERENCE((*config), comparator, int16_t); + break; + case 3: + SCALE_MULTI_COMP_REFERENCE((*config), comparator, int32_t); + break; + } + + free(comparator->config); + comparator->config= config; + comparator->config_size= 1 + offset; + + modify_processor_configuration(comparator, comparator->config_size); + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_delta_create(MblMwDataSignal *source, MblMwDeltaMode mode, float magnitude, + void *context, MblMwFnDataProcessor processor_created) { + if (source->length() > PROCESSOR_MAX_LENGTH) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + uint32_t scaled_magnitude= (uint32_t) number_to_firmware_converters.at(source->converter)(source, magnitude); + + DeltaConfig config; + *((uint8_t*) &config)= 0; + config.length= source->length() - 1; + config.is_signed= source->is_signed; + config.mode= mode; + memcpy(((uint8_t*)(&config)) + 1, &scaled_magnitude, sizeof(scaled_magnitude)); + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::DELTA), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_delta_set_reference(MblMwDataProcessor *delta, float previous_value) { + if (delta->type == DataProcessorType::DELTA) { + int32_t scaled_previous_value= (int32_t) number_to_firmware_converters.at(delta->converter)(delta, previous_value); + set_processor_state(delta, &scaled_previous_value, sizeof(scaled_previous_value)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_delta_modify_magnitude(MblMwDataProcessor *delta, float magnitude) { + if (delta->type == DataProcessorType::DELTA) { + uint32_t scaled_magnitude= (uint32_t) number_to_firmware_converters.at(delta->converter)(delta, magnitude); + memcpy(((uint8_t*)(delta->config)) + 1, &scaled_magnitude, sizeof(scaled_magnitude)); + + modify_processor_configuration(delta, sizeof(DeltaConfig)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +static int32_t create_math(MblMwDataSignal *source, MblMwMathOperation op, float rhs, uint8_t is_signed, + void *context, MblMwFnDataProcessor processor_created) { + if ((source->n_channels > 1 && source->owner->firmware_revision < MULTI_CHANNEL_MATH) || + (op == MBL_MW_MATH_OP_CONSTANT && source->owner->firmware_revision < CONST_MATH_OP)) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + int32_t scaled_rhs; + switch (op) { + case MBL_MW_MATH_OP_ADD: + case MBL_MW_MATH_OP_SUBTRACT: + case MBL_MW_MATH_OP_MODULUS: + scaled_rhs= (int32_t) number_to_firmware_converters.at(source->converter)(source, rhs); + break; + default: + scaled_rhs= (int32_t) rhs; + break; + } + + MathConfig config; + *((uint8_t*) &config)= 0; + config.input= source->channel_size - 1; + config.is_signed= is_signed; + config.operation= op; + config.n_channels= source->n_channels - 1; + + memcpy(((uint8_t*)(&config)) + 2, &scaled_rhs, sizeof(scaled_rhs)); + + auto new_processor = MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::MATH), &config); + ((MathConfig*) new_processor->config)->output= new_processor->channel_size - 1; + create_processor(source, new_processor, context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_math_create(MblMwDataSignal *source, MblMwMathOperation op, float rhs, + void *context, MblMwFnDataProcessor processor_created) { + if (source->is_signed) { + return mbl_mw_dataprocessor_math_create_signed(source, op, rhs, context, processor_created); + } else { + return mbl_mw_dataprocessor_math_create_unsigned(source, op, rhs, context, processor_created); + } +} + +int32_t mbl_mw_dataprocessor_math_create_signed(MblMwDataSignal *source, MblMwMathOperation op, float rhs, + void *context, MblMwFnDataProcessor processor_created) { + return create_math(source, op, rhs, 1, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_math_create_unsigned(MblMwDataSignal *source, MblMwMathOperation op, float rhs, + void *context, MblMwFnDataProcessor processor_created) { + return create_math(source, op, rhs, 0, context, processor_created); +} + +int32_t mbl_mw_dataprocessor_math_modify_rhs(MblMwDataProcessor *math, float rhs) { + if (math->type == DataProcessorType::MATH) { + MathConfig* current_config= (MathConfig*) math->config; + + int32_t scaled_rhs; + switch (current_config->operation) { + case MBL_MW_MATH_OP_ADD: + case MBL_MW_MATH_OP_SUBTRACT: + case MBL_MW_MATH_OP_MODULUS: + scaled_rhs= (int32_t) number_to_firmware_converters.at(math->converter)(math, rhs); + break; + default: + scaled_rhs= (int32_t) rhs; + break; + } + memcpy(((uint8_t*)(current_config)) + 2, &scaled_rhs, sizeof(scaled_rhs)); + + modify_processor_configuration(math, sizeof(MathConfig)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_math_modify_rhs_signal(MblMwDataProcessor *math, MblMwDataSignal* rhs_signal) { + if (math->type == DataProcessorType::MATH) { + MathConfig *current_config= (MathConfig*) math->config; + + memset(((uint8_t*)(current_config)) + 2, 0, sizeof(current_config->rhs)); + + EventDataParameter signal_data_token= {rhs_signal->length(), rhs_signal->offset, 4}; + + set_data_token(math->owner, &signal_data_token); + modify_processor_configuration(math, sizeof(MathConfig)); + clear_data_token(math->owner); + + return MBL_MW_STATUS_OK; + } + + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +uint8_t get_packer_length(const MblMwDataProcessor* source) { + return ((PackerConfig*)source->config)->length + 1; +} + +uint8_t get_packer_count(const MblMwDataProcessor* source) { + return ((PackerConfig*)source->config)->count + 1; +} + +int32_t mbl_mw_dataprocessor_packer_create(MblMwDataSignal *source, uint8_t count, void *context, MblMwFnDataProcessor processor_created) { + if (source->length() * count + 3 >= BLE_PACKET_SIZE) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + PackerConfig config; + memset(&config, 0, sizeof(PackerConfig)); + config.length = source->length() - 1; + config.count = count - 1; + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::PACKER), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_passthrough_create(MblMwDataSignal *source, MblMwPassthroughMode mode, uint16_t count, + void *context, MblMwFnDataProcessor processor_created) { + PassthroughConfig config; + config.mode= mode; + memcpy(((uint8_t*)(&config)) + 1, &count, sizeof(count)); + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::PASSTHROUGH), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_passthrough_set_count(MblMwDataProcessor *passthrough, uint16_t new_count) { + if (passthrough->type == DataProcessorType::PASSTHROUGH) { + set_processor_state(passthrough, &new_count, sizeof(new_count)); + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_passthrough_modify(MblMwDataProcessor *passthrough, MblMwPassthroughMode mode, uint16_t count) { + if (passthrough->type == DataProcessorType::PASSTHROUGH) { + PassthroughConfig* current_config= (PassthroughConfig*) passthrough->config; + + current_config->mode= mode; + memcpy(((uint8_t*)(current_config)) + 1, &count, sizeof(count)); + + modify_processor_configuration(passthrough, sizeof(PassthroughConfig)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_pulse_create(MblMwDataSignal *source, MblMwPulseOutput output, float threshold, + uint16_t width, void *context, MblMwFnDataProcessor processor_created) { + if (source->length() > PROCESSOR_MAX_LENGTH) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + int32_t scaled_threshold= (int32_t) number_to_firmware_converters.at(source->converter)(source, threshold); + + PulseDetectorConfig config; + config.length= source->length() - 1; + config.trigger_mode= 0; + config.output_mode= output; + memcpy(((uint8_t*)(&config)) + 3, &scaled_threshold, sizeof(scaled_threshold)); + memcpy(((uint8_t*)(&config)) + 7, &width, sizeof(width)); + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::PULSE), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_pulse_modify(MblMwDataProcessor *pulse, float threshold, uint16_t width) { + if (pulse->type == DataProcessorType::PULSE) { + int32_t scaled_threshold= (int32_t) number_to_firmware_converters.at(pulse->converter)(pulse, threshold); + memcpy(((uint8_t*)(pulse->config)) + 3, &scaled_threshold, sizeof(scaled_threshold)); + memcpy(((uint8_t*)(pulse->config)) + 7, &width, sizeof(width)); + + modify_processor_configuration(pulse, sizeof(PulseDetectorConfig)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_sample_create(MblMwDataSignal *source, uint8_t bin_size, void *context, MblMwFnDataProcessor processor_created) { + uint8_t maxLength = source->owner->module_info.at(MBL_MW_MODULE_DATA_PROCESSOR).revision < 2 ? 4 : 16; + if (source->length() > maxLength) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + SampleDelayConfig config; + config.length= source->length() - 1; + config.bin_size= bin_size; + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::SAMPLE), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_sample_modify_bin_size(MblMwDataProcessor *sample_delay, uint8_t bin_size) { + if (sample_delay->type == DataProcessorType::SAMPLE) { + SampleDelayConfig* current_config = (SampleDelayConfig*) sample_delay->config; + current_config->bin_size= bin_size; + modify_processor_configuration(sample_delay, sizeof(SampleDelayConfig)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +int32_t mbl_mw_dataprocessor_threshold_create(MblMwDataSignal *source, MblMwThresholdMode mode, float boundary, + float hysteresis, void *context, MblMwFnDataProcessor processor_created) { + if (source->length() > PROCESSOR_MAX_LENGTH) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + int32_t scaled_boundary= (int32_t) number_to_firmware_converters.at(source->converter)(source, boundary); + uint16_t scaled_hysteresis= (uint16_t) number_to_firmware_converters.at(source->converter)(source, hysteresis); + + ThresholdConfig config; + *((uint8_t*) &config)= 0; + config.length= source->length() - 1; + config.is_signed= source->is_signed; + config.mode= mode; + + memcpy(((uint8_t*)(&config)) + 1, &scaled_boundary, sizeof(scaled_boundary)); + memcpy(((uint8_t*)(&config)) + 5, &scaled_hysteresis, sizeof(scaled_hysteresis)); + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::THRESHOLD), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_threshold_modify_boundary(MblMwDataProcessor *threshold, float boundary, float hysteresis) { + if (threshold->type == DataProcessorType::THRESHOLD) { + int32_t scaled_boundary= (int32_t) number_to_firmware_converters.at(threshold->converter)(threshold, boundary); + uint16_t scaled_hysteresis= (uint16_t) number_to_firmware_converters.at(threshold->converter)(threshold, hysteresis); + + memcpy(((uint8_t*)(threshold->config)) + 1, &scaled_boundary, sizeof(scaled_boundary)); + memcpy(((uint8_t*)(threshold->config)) + 5, &scaled_hysteresis, sizeof(scaled_hysteresis)); + + modify_processor_configuration(threshold, sizeof(ThresholdConfig)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +const uint8_t TIME_PASSTHROUGH_REVISION = 1; + +int32_t mbl_mw_dataprocessor_time_create(MblMwDataSignal *source, MblMwTimeMode mode, uint32_t period, + void *context, MblMwFnDataProcessor processor_created) { + bool hasPassthrough = source->owner->module_info.at(MBL_MW_MODULE_DATA_PROCESSOR).revision >= TIME_PASSTHROUGH_REVISION; + if (source->length() > PROCESSOR_MAX_LENGTH && (!hasPassthrough || mode == MBL_MW_TIME_DIFFERENTIAL)) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + TimeDelayConfig config; + *((uint8_t*) &config)= 0; + config.length= source->length() - 1; + config.mode= (mode == MBL_MW_TIME_ABSOLUTE) && hasPassthrough ? 2 : mode; + + memcpy(((uint8_t*)(&config)) + 1, &period, sizeof(period)); + + create_processor(source, MblMwDataProcessor::transform(source, type_to_id.at(DataProcessorType::TIME), &config), context, processor_created); + + return MBL_MW_STATUS_OK; +} + +int32_t mbl_mw_dataprocessor_time_modify_period(MblMwDataProcessor *time_delay, uint32_t period) { + if (time_delay->type == DataProcessorType::TIME) { + memcpy(((uint8_t*)(time_delay->config)) + 1, &period, sizeof(period)); + modify_processor_configuration(time_delay, sizeof(TimeDelayConfig)); + + return MBL_MW_STATUS_OK; + } + return MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE; +} + +struct FuseCreeateState { + vector inputs; + MblMwDataSignal *source; + void* context; + MblMwFnDataProcessor processor_created; + MblMwDataSignal** ops; + uint32_t n_ops, i; +}; + +static void buffer_crate_handler(void *context, MblMwDataProcessor* processor) { + auto casted = (FuseCreeateState*) context; + if (processor != nullptr) { + casted->i++; + casted->inputs.push_back(processor); + + if (casted->i == casted->n_ops) { + FuseConfig config; + memset(&config, 0, sizeof(FuseConfig)); + config.count = casted->n_ops; + + for(size_t i = 0; i < casted->inputs.size(); i++) { + config.references[i] = casted->inputs[i]->header.data_id; + } + + create_processor(casted->source, MblMwDataProcessor::transform(casted->source, type_to_id.at(DataProcessorType::FUSER), &config), casted->context, casted->processor_created); + delete casted; + } else { + mbl_mw_dataprocessor_buffer_create(casted->ops[casted->i], context, buffer_crate_handler); + } + } else { + casted->processor_created(casted->context, processor); + delete casted; + } +} + +const uint8_t FUSER_REVISION = 1; + +int32_t mbl_mw_dataprocessor_fuser_create(MblMwDataSignal *source, MblMwDataSignal** ops, uint32_t n_ops, void *context, MblMwFnDataProcessor processor_created) { + if (source->owner->module_info.at(MBL_MW_MODULE_DATA_PROCESSOR).revision < FUSER_REVISION) { + return MBL_MW_STATUS_ERROR_UNSUPPORTED_PROCESSOR; + } + + FuseCreeateState* fuse_context = new FuseCreeateState; + fuse_context->source = source; + fuse_context->context = context; + fuse_context->processor_created = processor_created; + fuse_context->ops = ops; + fuse_context->n_ops = n_ops; + fuse_context->i = 0; + + return mbl_mw_dataprocessor_buffer_create(ops[0], fuse_context, buffer_crate_handler); +} \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.h new file mode 100644 index 0000000..ed0c64e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.h @@ -0,0 +1,140 @@ +#pragma once + +#include "metawear/core/cpp/version.h" + +#include "metawear/processor/dataprocessor_fwd.h" + +#include + +const uint8_t ACCOUNTER_COUNT = 0, ACCOUNTER_TIME = 1; + +struct AccounterConfig { + uint8_t mode:4; + uint8_t length:2; + uint8_t :2; + uint8_t prescale:4; + uint8_t :4; +}; + +uint8_t get_accounter_type(const MblMwDataProcessor* source); +uint8_t get_accounter_length(const MblMwDataProcessor* source); +uint8_t get_accounter_prescale(const MblMwDataProcessor* source); + +const uint8_t ACCUMULATOR_SUM = 0, ACCUMULATOR_COUNT = 1; + +struct AccumulatorConfig { + uint8_t output:2; + uint8_t input:2; + uint8_t mode:3; +}; + +const uint8_t HPF_REVISION = 2, USE_HPF = 1; + +struct AverageConfig { + uint8_t output:2; + uint8_t input:2; + uint8_t :1; + uint8_t mode:1; + uint8_t :2; + uint8_t size; + uint8_t count; +}; + +struct BufferConfig { + uint8_t length:5; +}; + +const int8_t COMBINER_RMS= 0, COMBINER_RSS= 1; + +struct CombinerConfig { + uint8_t output:2; + uint8_t input:2; + uint8_t count:3; + uint8_t is_signed:1; + uint8_t mode; +}; + +const Version MULTI_COMPARE(1, 2, 3); + +struct ComparatorConfig { + uint8_t is_signed; + uint8_t operation; + uint8_t :8; + uint8_t reference[4]; +}; + +struct MultiComparatorConfig { + uint8_t is_signed:1; + uint8_t length:2; + uint8_t operation:3; + uint8_t mode:2; + uint8_t references[12]; +}; + +struct DeltaConfig { + uint8_t length:2; + uint8_t is_signed:1; + uint8_t mode:3; + uint8_t magnitude[4]; +}; + +const Version MULTI_CHANNEL_MATH(1, 1, 0), CONST_MATH_OP(1, 1, 0); + +struct MathConfig { + uint8_t output:2; + uint8_t input:2; + uint8_t is_signed:1; + uint8_t :3; + uint8_t operation; + uint8_t rhs[4]; + uint8_t n_channels; +}; + +struct PackerConfig { + uint8_t length:5; + uint8_t :3; + uint8_t count:5; + uint8_t :3; +}; + +uint8_t get_packer_count(const MblMwDataProcessor* source); +uint8_t get_packer_length(const MblMwDataProcessor* source); + +struct PassthroughConfig { + uint8_t mode; + uint8_t count[2]; +}; + +struct PulseDetectorConfig { + uint8_t length; + uint8_t trigger_mode; + uint8_t output_mode; + uint8_t threshold[4]; + uint8_t width[2]; +}; + +struct SampleDelayConfig { + uint8_t length; + uint8_t bin_size; +}; + +struct ThresholdConfig { + uint8_t length:2; + uint8_t is_signed:1; + uint8_t mode:3; + uint8_t boundary[4]; + uint8_t hysteresis[2]; +}; + +struct TimeDelayConfig { + uint8_t length:3; + uint8_t mode:3; + uint8_t :2; + uint8_t period[4]; +}; + +struct FuseConfig { + uint8_t count:4; + uint8_t:4; + uint8_t references[12]; +}; \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_private.h new file mode 100644 index 0000000..57c1a93 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_private.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/processor/dataprocessor_fwd.h" + +const uint8_t PROCESSOR_MAX_LENGTH = 4; + +enum class DataProcessorType : uint8_t { + ACCUMULATOR, + AVERAGE, + BUFFER, + COMPARATOR, + COUNTER, + DELTA, + MATH, + PASSTHROUGH, + PULSE, + RMS, + RSS, + SAMPLE, + THRESHOLD, + TIME, + ACCOUNTER, + PACKER, + FUSER +}; + +extern std::unordered_map type_to_id; + +struct ProcessorEntry { + uint8_t id, offset, length; + ResponseHeader source; + std::vector config; +}; + +typedef void(*ProcessorEntriesHandler)(MblMwMetaWearBoard* board, std::stack& entries); + +struct MblMwDataProcessor : public MblMwDataSignal { + static MblMwDataProcessor* transform(const MblMwDataSignal* input, uint8_t id, const void* config); + static MblMwDataProcessor* transform(const MblMwDataSignal* input, const std::vector& config); + + MblMwDataProcessor(uint8_t** state_stream, MblMwMetaWearBoard *owner); + MblMwDataProcessor(const MblMwDataSignal& signal); + virtual ~MblMwDataProcessor(); + + virtual void subscribe(); + virtual void unsubscribe(); + + virtual void serialize(std::vector& state) const; + virtual void create_uri(std::stringstream& uri) const; + MblMwDataProcessor* parent() const; + + uint8_t parent_id; + MblMwDataSignal* state; + const MblMwDataSignal* input; + void* config; + uint8_t config_size; + std::vector consumers; + DataProcessorType type; +}; + +void init_dataprocessor_module(MblMwMetaWearBoard* board); +void free_dataprocessor_module(void* state); +void create_processor(MblMwDataSignal* source, MblMwDataProcessor* processor, void *context, MblMwFnDataProcessor processor_created); +void set_processor_state(MblMwDataProcessor *processor, void* new_state, uint8_t size); +void modify_processor_configuration(MblMwDataProcessor *processor, uint8_t size); +void sync_processor_chain(MblMwMetaWearBoard* board, uint8_t id, ProcessorEntriesHandler handler); +void disconnect_dataprocessor(MblMwMetaWearBoard* board); +MblMwDataProcessor* lookup_processor(const MblMwMetaWearBoard* board, uint8_t id); + +namespace std { + +template <> +struct hash { + size_t operator()(const DataProcessorType& key) const; +}; + +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_register.h new file mode 100644 index 0000000..fad7f9c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_register.h @@ -0,0 +1,11 @@ +#pragma once + +enum class DataProcessorRegister : uint8_t { + ADD= 2, + NOTIFY, + STATE, + PARAMETER, + REMOVE, + NOTIFY_ENABLE, + REMOVE_ALL +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/dataprocessor.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/dataprocessor.h new file mode 100644 index 0000000..291b934 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/dataprocessor.h @@ -0,0 +1,45 @@ +/** + * @copyright MbientLab License + * @file dataprocessor.h + * @brief Interacts with an onboard data processor + */ +#pragma once + +#include "dataprocessor_fwd.h" +#include "metawear/core/datasignal_fwd.h" +#include "metawear/core/metawearboard_fwd.h" +#include "metawear/platform/dllmarker.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get the data signal representing a processor's internal state. + * Processors that have an internal state are: accumulator, buffer, counter, delta, and passthrough. + * @param processor Processor to access + * @return Pointer to the data signal, null if the processor does not have an internal state + */ +METAWEAR_API MblMwDataSignal* mbl_mw_dataprocessor_get_state_data_signal(const MblMwDataProcessor* processor); +/** + * Removes a data processor and its consumers from the board + * @param processor Processor to remove + */ +METAWEAR_API void mbl_mw_dataprocessor_remove(MblMwDataProcessor *processor); +/** + * Retrieves the id value identifying the processor + * @param processor Processor to lookup + * @return Numerical id of the processor + */ +METAWEAR_API uint8_t mbl_mw_dataprocessor_get_id(const MblMwDataProcessor* processor); +/** + * Looks up the MblMwDataProcessor object corresponding to the id + * @param board Board to search on + * @param id Numerical id to lookup + * @return Data processor object identified by the id, null if no object is found + */ +METAWEAR_API MblMwDataProcessor* mbl_mw_dataprocessor_lookup_id(const MblMwMetaWearBoard* board, uint8_t id); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/dataprocessor_fwd.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/dataprocessor_fwd.h new file mode 100644 index 0000000..6914d4f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/dataprocessor_fwd.h @@ -0,0 +1,23 @@ +/** + * @copyright MbientLab License + * @file dataprocessor_fwd.h + * @brief Forward declaration for the MblMwDataProcessor type + */ +#pragma once + +/** + * Data signal from the on board data processor. An MblMwDataProcessor pointer can be casted as an + * MblMwDataSignal pointer and used with any function tht accepts an MblMwdDataSignal. + */ +#ifdef __cplusplus +struct MblMwDataProcessor; +#else +typedef struct MblMwDataProcessor MblMwDataProcessor; +#endif + +/** + * Definition for callback functions that accept an MblMwDataProcessor pointer + * @param context Pointer to the context the enclosing function was called with + * @param processor Processor to be used with the function + */ +typedef void (*MblMwFnDataProcessor)(void *context, MblMwDataProcessor* processor); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/delta.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/delta.h new file mode 100644 index 0000000..5807438 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/delta.h @@ -0,0 +1,54 @@ +/** + * @copyright MbientLab License + * @file delta.h + * @brief Only allows data through that is a min distance from a reference value + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Output modes of the data processor + */ +typedef enum { + MBL_MW_DELTA_MODE_ABSOLUTE = 0, ///< Return the data as is + MBL_MW_DELTA_MODE_DIFFERENTIAL, ///< Return the difference between the input and the reference value + MBL_MW_DELTA_MODE_BINARY ///< Return 1 if input > reference, -1 if input < reference +} MblMwDeltaMode; + +/** + * Create a delta processor which looks for changes in the input. + * Only allows data through that is a min distance from a reference value. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param mode Output mode of the processor + * @param magnitude Min distance from the reference value to allow the input to pass + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_delta_create(MblMwDataSignal *source, MblMwDeltaMode mode, float magnitude, + void *context, MblMwFnDataProcessor processor_created); +/** + * Sets the reference value of the processor. + * @param delta Delta processor to modify + * @param previous_value Min distance from the reference value to allow the input to pass + * @return MBL_MW_STATUS_OK if processor state was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-delta processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_delta_set_reference(MblMwDataProcessor *delta, float previous_value); +/** + * Modifies the magnitude that allows data through + * @param delta Delta processor to modify + * @param magnitude Min distance from the reference value to allow the input to pass + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-delta processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_delta_modify_magnitude(MblMwDataProcessor *delta, float magnitude); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/fuser.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/fuser.h new file mode 100644 index 0000000..de11df2 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/fuser.h @@ -0,0 +1,30 @@ +/** + * @copyright MbientLab License + * @file fuser.h + * @brief Combine data from multiple data sources into 1 data packet + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Create a fuser processor which fuses signals or processors together. + * Combine data from multiple data sources into 1 data packet. + * Popular for combining gyro and acc data into 1 packet. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param ops Array of data signals to combine into 1 message + * @param n_ops Number of items in the array + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_fuser_create(MblMwDataSignal *source, MblMwDataSignal** ops, uint32_t n_ops, + void *context, MblMwFnDataProcessor processor_created); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/math.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/math.h new file mode 100644 index 0000000..e08b332 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/math.h @@ -0,0 +1,86 @@ +/** + * @copyright MbientLab License + * @file math.h + * @brief Performs arithmetic on sensor data + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Available operations for the math processor + */ +typedef enum { + MBL_MW_MATH_OP_ADD= 1, ///< Computes input + rhs + MBL_MW_MATH_OP_MULTIPLY, ///< Computes input * rhs + MBL_MW_MATH_OP_DIVIDE, ///< Computes input / rhs + MBL_MW_MATH_OP_MODULUS, ///< Computes input % rhs + MBL_MW_MATH_OP_EXPONENT, ///< Computes input ^ rhs + MBL_MW_MATH_OP_SQRT, ///< Computes sqrt(input) + MBL_MW_MATH_OP_LSHIFT, ///< Computes input << rhs + MBL_MW_MATH_OP_RSHIFT, ///< Computes input >> rhs + MBL_MW_MATH_OP_SUBTRACT, ///< Computes input - rhs + MBL_MW_MATH_OP_ABS_VALUE, ///< Computes |input| + MBL_MW_MATH_OP_CONSTANT ///< Replaces input with rhs +} MblMwMathOperation; + +/** + * Create a math processor where signed/unsigned operation is inferred. + * Performs simple arithmetic on sensor data. See MblMwMathOperation for allowed ops. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param op Math operation to compute + * @param rhs Right hand side of the operation that requires 2 inputs + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_math_create(MblMwDataSignal *source, MblMwMathOperation op, float rhs, + void *context, MblMwFnDataProcessor processor_created); +/** + * Create a math processor using signed operations. + * Performs simple arithmetic on sensor data. See MblMwMathOperation for allowed ops. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param op Math operation to compute + * @param rhs Right hand side of the operation that requires 2 inputs + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_math_create_signed(MblMwDataSignal *source, MblMwMathOperation op, float rhs, + void *context, MblMwFnDataProcessor processor_created); +/** + * Create a math processor using unsigned operations. + * Performs simple arithmetic on sensor data. See MblMwMathOperation for allowed ops. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param op Math operation to compute + * @param rhs Right hand side of the operation that requires 2 inputs + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_math_create_unsigned(MblMwDataSignal *source, MblMwMathOperation op, float rhs, + void *context, MblMwFnDataProcessor processor_created); +/** + * Modify the configuration of a math processor, changing the right side value of the operation + * @param math Math processor to modify + * @param rhs New right hand side of the operation + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-math processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_math_modify_rhs(MblMwDataProcessor *math, float rhs); +/** + * Modify the configuration of a math processor for a feedback or feedforward loop + * @param math Math processor to modify + * @param rhs_signal Data signal supplying the rhs value of the operation + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-math processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_math_modify_rhs_signal(MblMwDataProcessor *math, MblMwDataSignal* rhs_signal); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/packer.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/packer.h new file mode 100644 index 0000000..6e97e30 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/packer.h @@ -0,0 +1,28 @@ +/** + * @copyright MbientLab License + * @file packer.h + * @brief Combines multiple data values into 1 BLE packet + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Create a packer for the input signal. + * Combines multiple data values into 1 BLE packet. + * Can be used to combine 3 accelerometer data entries into 1 packet. Used to ultra fast streaming. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param count Number of inputs to pack into 1 BLE packet + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_packer_create(MblMwDataSignal *source, uint8_t count, void *context, MblMwFnDataProcessor processor_created); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/passthrough.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/passthrough.h new file mode 100644 index 0000000..1796c39 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/passthrough.h @@ -0,0 +1,57 @@ +/** + * @copyright MbientLab License + * @file passthrough.h + * @brief Gate that only allows data though based on a user configured internal state + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Operation modes for the processor + */ +typedef enum { + MBL_MW_PASSTHROUGH_MODE_ALL = 0, ///< Allow all data through + MBL_MW_PASSTHROUGH_MODE_CONDITIONAL, ///< Only allow data through if count > 0 + MBL_MW_PASSTHROUGH_MODE_COUNT ///< Only allow a fixed number of data samples through +} MblMwPassthroughMode; + +/** + * Create a passthrough processor. + * On a pass-count, only the count # of samples will go through and then the processor will shut off. + * On a pass-conditional, if the count=0, all data is blocked. if the count>0, all data is passed. + * Gate that only allows data though based on a user configured internal state. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param mode Processor's operation mode + * @param count Internal count to initial the processor with + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_passthrough_create(MblMwDataSignal *source, MblMwPassthroughMode mode, uint16_t count, + void *context, MblMwFnDataProcessor processor_created); +/** + * Modify the internal count of the passthrough processor + * @param passthrough Passthrough processor to modify + * @param new_count New internal count + * @return MBL_MW_STATUS_OK if processor state was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-passthrough processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_passthrough_set_count(MblMwDataProcessor *passthrough, uint16_t new_count); +/** + * Modify the passthrough configuration + * @param passthrough Passthrough processor to update + * @param mode New operation mode to use + * @param count New initial count + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-passthrough processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_passthrough_modify(MblMwDataProcessor *passthrough, MblMwPassthroughMode mode, uint16_t count); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/processor_common.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/processor_common.h new file mode 100644 index 0000000..675c367 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/processor_common.h @@ -0,0 +1,5 @@ +#include + +#include "dataprocessor_fwd.h" +#include "metawear/core/datasignal_fwd.h" +#include "metawear/platform/dllmarker.h" diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/pulse.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/pulse.h new file mode 100644 index 0000000..6cda6e6 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/pulse.h @@ -0,0 +1,49 @@ +/** + * @copyright MbientLab License + * @file pulse.h + * @brief Detects and quantifies a pulse over the input values + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Output modes for the processor + */ +typedef enum { + MBL_MW_PULSE_OUTPUT_WIDTH = 0, ///< Return number of samples in the pulse + MBL_MW_PULSE_OUTPUT_AREA, ///< Return a sum of all data points in the pulse + MBL_MW_PULSE_OUTPUT_PEAK, ///< Return the highest value in the pulse + MBL_MW_PULSE_OUTPUT_ON_DETECTION ///< Return a 0x01 as soon as a pulse is detected +} MblMwPulseOutput; + +/** + * Create a pulse detector. + * Detects and quantifies a pulse over the input values using the threshold and width specified. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param output Output type of the processor + * @param threshold Value the data must exceed for a valid pulse + * @param width Number of samples that must exceed the threshold for a valid pulse + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_pulse_create(MblMwDataSignal *source, MblMwPulseOutput output, + float threshold, uint16_t width, void *context, MblMwFnDataProcessor processor_created); +/** + * Modify the configuration of a pulse detector + * @param pulse Pulse detector to modify + * @param threshold New threshold of the detector + * @param width New width of the detector + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non pulse detector was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_pulse_modify(MblMwDataProcessor *pulse, float threshold, uint16_t width); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/rms.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/rms.h new file mode 100644 index 0000000..0556264 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/rms.h @@ -0,0 +1,27 @@ +/** + * @copyright MbientLab License + * @file rms.h + * @brief Computes the root mean square of the input + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Create an rms processor. + * Computes the root mean square of the input. + * Works on inputs such as acc, gyro, and magnetometer data (x,y,z) + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_rms_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/rss.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/rss.h new file mode 100644 index 0000000..f57c1b6 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/rss.h @@ -0,0 +1,27 @@ +/** + * @copyright MbientLab License + * @file rss.h + * @brief Computes the root sum square of the input + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Create an rss processor. + * Computes the root sum square of the input. + * Works on inputs such as acc, gyro, and magnetometer data (x,y,z) + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_rss_create(MblMwDataSignal *source, void *context, MblMwFnDataProcessor processor_created); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/sample.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/sample.h new file mode 100644 index 0000000..f1fc8cf --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/sample.h @@ -0,0 +1,37 @@ +/** + * @copyright MbientLab License + * @file sample.h + * @brief Holds data until a certain amount has been collected + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Create a sample delay processor. + * Holds data until a certain amount (bin_size) has been collected. + * Can be used to delay the input into another processor. + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param bin_size Number of samples to hold before letting data through + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_sample_create(MblMwDataSignal *source, uint8_t bin_size, + void *context, MblMwFnDataProcessor processor_created); +/** + * Modify the bin size of a sample delay processor + * @param sample_delay Sample processor to modify + * @param bin_size Number of samples to hold before letting data through + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non sample delay processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_sample_modify_bin_size(MblMwDataProcessor *sample_delay, uint8_t bin_size); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/threshold.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/threshold.h new file mode 100644 index 0000000..7792069 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/threshold.h @@ -0,0 +1,48 @@ +/** + * @copyright MbientLab License + * @file threshold.h + * @brief Allows data through that crosses a boundary + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Output modes of the processor + */ +typedef enum { + MBL_MW_THRESHOLD_MODE_ABSOLUTE = 0, ///< Return the data as is + MBL_MW_THRESHOLD_MODE_BINARY ///< Return 1 if data > bounday, -1 if data < boundary +} MblMwThresholdMode; + +/** + * Create a threshold processor. + * Allows data through that crosses a boundary (threshold) according to MblMwThresholdMode + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param mode Processor output mode (absolute mode, output is value | binary mode output is 1 rising edge, -1 if falling) + * @param boundary Limit (threshold) that triggers an event when data crosses it + * @param hysteresis Min distance (error/diff) between the limit and value to signal a successful crossing + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_threshold_create(MblMwDataSignal *source, MblMwThresholdMode mode, float boundary, + float hysteresis, void *context, MblMwFnDataProcessor processor_created); +/** + * Modifies the threshold processor configuration + * @param threshold Threshold processor to modify + * @param boundary Limit (threshold) that triggers an event when data crosses it + * @param hysteresis Min distance (error/diff) between the limit and value to signal a successful crossing + * @return MBL_MW_STATUS_OK if processor configuration was updated, MBL_MW_STATUS_WARNING_INVALID_PROCESSOR_TYPE if + * a non-threshold processor was passed in + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_threshold_modify_boundary(MblMwDataProcessor *threshold, float boundary, + float hysteresis); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/time.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/time.h new file mode 100644 index 0000000..6eb611b --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/time.h @@ -0,0 +1,44 @@ +/** + * @copyright MbientLab License + * @file time.h + * @brief Periodically allow data through + */ +#pragma once + +#include "processor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Output modes for the processor + */ +typedef enum { + MBL_MW_TIME_ABSOLUTE = 0, ///< Returns the data as is + MBL_MW_TIME_DIFFERENTIAL ///< Returns the difference between the current and previous value +} MblMwTimeMode; + +/** + * Creates a time delay processor. + * Can be used to periodically allow data through. + * Can be used to slowly (low freq/sampling rate) get data from sensors (i.e count to 30 and take a temp reading) + * A pointer representing the processor will be passed back to the user via a callback function. + * @param source Data signal providing the input for the processor + * @param mode Operation mode of the processor + * @param period How often to allow data through, in milliseconds + * @param context Pointer to additional data for the callback function + * @param processor_created Callback function to be executed when the processor is created + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_time_create(MblMwDataSignal *source, MblMwTimeMode mode, uint32_t period, + void *context, MblMwFnDataProcessor processor_created); +/** + * Modify the configuration of the time delay processor + * @param time_delay Time delay processor to modify + * @param period How often to allow data through, in milliseconds + */ +METAWEAR_API int32_t mbl_mw_dataprocessor_time_modify_period(MblMwDataProcessor *time_delay, uint32_t period); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer.h new file mode 100644 index 0000000..279a8ab --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer.h @@ -0,0 +1,95 @@ +/** + * @copyright MbientLab License + * @file accelerometer.h + * @brief Generic class providing high level access to an accelerometer + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//@{ +/** Indices for component values of the acceleration data signal, used with mbl_mw_datasignal_get_component */ +const uint8_t MBL_MW_ACC_ACCEL_X_AXIS_INDEX = 0, + MBL_MW_ACC_ACCEL_Y_AXIS_INDEX = 1, + MBL_MW_ACC_ACCEL_Z_AXIS_INDEX = 2; +//@} + +/** + * Retrieves the data signal representing acceleration data + * This signal is timestamp,x,y,z acc data + * @param board Board to retrieve the signal from + * @return Pointer to the acceleration data signal + * MblMwCartesianFloat is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_get_acceleration_data_signal(const MblMwMetaWearBoard *board); +/** + * @deprecated As of v0.8.0 and will be removed in v1.0.0. Use mbl_mw_acc_get_packed_acceleration_data_signal instead. + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_get_high_freq_acceleration_data_signal(const MblMwMetaWearBoard *board); +/** + * Variant of acceleration data that packs multiple data samples into 1 BLE packet to increase the + * data throughput. This data signal cannot be used with data processing or logging, only with streaming. + * This signal is timestamp,x,y,z,x,y,z,x,y,z acc data (it packs three acc data points in one timestamp) + * @return Pointer to the data signal + * [MblMwCartesianFloat, MblMwCartesianFloat, MblMwCartesianFloat] is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_get_packed_acceleration_data_signal(const MblMwMetaWearBoard *board); +/** + * Sets the output data rate. If an invalid odr is used, the closest valid value will be used. + * The ODR sets the output data frequency in Hz. + * @param board Board to configure + * @param odr Output data rate, in Hz + */ +METAWEAR_API float mbl_mw_acc_set_odr(MblMwMetaWearBoard *board, float odr); +/** + * Sets the full scale range. IF an invalid range is used, the closet valid value will be used. + * The range is in units of Gs + * @param board Board to configure + * @param range Sampling range, in g's + */ +METAWEAR_API float mbl_mw_acc_set_range(MblMwMetaWearBoard *board, float range); +/** + * Writes the acceleration settings to the board + * Applies the ODR and RANGE values set in set_range() and set_odr(). + * @param board Board to configure + */ +METAWEAR_API void mbl_mw_acc_write_acceleration_config(const MblMwMetaWearBoard* board); +/** + * Pulls the current accelerometer output data rate and data range from the sensor + * Reads the ODR and RANGE values set in the sensor. + * This is a debug function, the data is return in the context ptr as AccBmi160Config->acc/AccBmi270Config->acc/Mma8452qConfig->acc + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param completed Callback function that is executed when the task is finished + */ +METAWEAR_API void mbl_mw_acc_read_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed); +/** + * Switches the accelerometer to active mode + * @param board Board the accelerometer is on + */ +METAWEAR_API void mbl_mw_acc_start(const MblMwMetaWearBoard *board); +/** + * Switches the accelerometer to standby mode + * @param board Board the accelerometer is on + */ +METAWEAR_API void mbl_mw_acc_stop(const MblMwMetaWearBoard *board); +/** + * Enables acceleration sampling + * The board will start gathering data from the accelerometer + * @param board Board to enable acceleration sampling on + */ +METAWEAR_API void mbl_mw_acc_enable_acceleration_sampling(const MblMwMetaWearBoard *board); +/** + * Disables acceleration sampling + * The board will stop gathering data from the accelerometer + * @param board Board to disable acceleration sampling on + */ +METAWEAR_API void mbl_mw_acc_disable_acceleration_sampling(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer_bosch.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer_bosch.h new file mode 100644 index 0000000..20439b5 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer_bosch.h @@ -0,0 +1,781 @@ +/** + * @copyright MbientLab License + * @file accelerometer_bosch.h + * @brief Interacts with the supported Bosch accelerometers, currently BMI270, BMI160 and BMA255 + * @details The BMI160 and BMA255 sensors are identical except for the output data rates. Functions that are generic for + * both accelerometers have "bosch" in the name whereas functions specific to either accelerometer are contain their model + * i.e. "bmi160" or "bma255". + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Available wrist gestures on the BMI270 + */ +typedef enum { + MBL_MW_ACC_BOSCH_TYPEWRIST_NONE= 0, + MBL_MW_ACC_BOSCH_TYPEWRIST_WEARK_WAKEUP, + MBL_MW_ACC_BOSCH_TYPEWRIST_GESTURE, +} MblMwAccBoschTypewrist; + +/** + * Available activities on the BMI270 + */ +typedef enum { + MBL_MW_ACC_BOSCH_ACTIVITY_STILL= 0, + MBL_MW_ACC_BOSCH_ACTIVITY_WALKING, + MBL_MW_ACC_BOSCH_ACTIVITY_RUNNING, + MBL_MW_ACC_BOSCH_ACTIVITY_UNKNOWN +} MblMwAccBoschActivity; + +/** + * Available wrist gestures on the BMI270 + */ +typedef enum { + MBL_MW_ACC_BOSCH_GESTURE_UNKNOWN= 0, ///< Unknown gesture + MBL_MW_ACC_BOSCH_GESTURE_PUSH_ARM_DOWN, ///< Arm pushed down gesture + MBL_MW_ACC_BOSCH_GESTURE_PIVOT_UP, ///< Pivot up gesture + MBL_MW_ACC_BOSCH_GESTURE_SHAKE, ///< Shake/jiggle gesture + MBL_MW_ACC_BOSCH_GESTURE_ARM_FLICK_IN, ///< Arm flick in gesture + MBL_MW_ACC_BOSCH_GESTURE_ARM_FLICK_OUT ///< Arm flick out gesture +} MblMwAccBoschGesture; + +/** + * Available motion detectors on the Bosch accelerometers + */ +typedef enum { + MBL_MW_ACC_BOSCH_MOTION_SIGMOTION= 0, ///< Significant motion detector + MBL_MW_ACC_BOSCH_MOTION_NOMOTION, ///< No motion detector + MBL_MW_ACC_BOSCH_MOTION_ANYMOTION, ///< Any motion detector +} MblMwAccBoschMotion; + +/** + * Available g-ranges on the Bosch accelerometers + */ +typedef enum { + MBL_MW_ACC_BOSCH_RANGE_2G= 0, ///< +/- 2g + MBL_MW_ACC_BOSCH_RANGE_4G, ///< +/- 4g + MBL_MW_ACC_BOSCH_RANGE_8G, ///< +/- 8g + MBL_MW_ACC_BOSCH_RANGE_16G ///< +/- 16g +} MblMwAccBoschRange; + +/** + * Available ouput data rates on the BMI160 accelerometer + */ +typedef enum { + MBL_MW_ACC_BMI160_ODR_0_78125Hz= 0, + MBL_MW_ACC_BMI160_ODR_1_5625Hz, + MBL_MW_ACC_BMI160_ODR_3_125Hz, + MBL_MW_ACC_BMI160_ODR_6_25Hz, + MBL_MW_ACC_BMI160_ODR_12_5Hz, + MBL_MW_ACC_BMI160_ODR_25Hz, + MBL_MW_ACC_BMI160_ODR_50Hz, + MBL_MW_ACC_BMI160_ODR_100Hz, + MBL_MW_ACC_BMI160_ODR_200Hz, + MBL_MW_ACC_BMI160_ODR_400Hz, + MBL_MW_ACC_BMI160_ODR_800Hz, + MBL_MW_ACC_BMI160_ODR_1600Hz +} MblMwAccBmi160Odr; + +/** + * Available ouput data rates on the BMA255 accelerometer + */ +typedef enum { + MBL_MW_ACC_BMA255_ODR_15_62Hz= 0, + MBL_MW_ACC_BMA255_ODR_31_26Hz, + MBL_MW_ACC_BMA255_ODR_62_5Hz, + MBL_MW_ACC_BMA255_ODR_125Hz, + MBL_MW_ACC_BMA255_ODR_250Hz, + MBL_MW_ACC_BMA255_ODR_500Hz, + MBL_MW_ACC_BMA255_ODR_1000Hz, + MBL_MW_ACC_BMA255_ODR_2000Hz +} MblMwAccBma255Odr; + +/** + * Available ouput data rates on the BMI270 accelerometer + */ +typedef enum { + MBL_MW_ACC_BMI270_ODR_0_78125Hz= 0, + MBL_MW_ACC_BMI270_ODR_1_5625Hz, + MBL_MW_ACC_BMI270_ODR_3_125Hz, + MBL_MW_ACC_BMI270_ODR_6_25Hz, + MBL_MW_ACC_BMI270_ODR_12_5Hz, + MBL_MW_ACC_BMI270_ODR_25Hz, + MBL_MW_ACC_BMI270_ODR_50Hz, + MBL_MW_ACC_BMI270_ODR_100Hz, + MBL_MW_ACC_BMI270_ODR_200Hz, + MBL_MW_ACC_BMI270_ODR_400Hz, + MBL_MW_ACC_BMI270_ODR_800Hz, + MBL_MW_ACC_BMI270_ODR_1600Hz +} MblMwAccBmi270Odr; + +/** + * Operation modes for the step counter algorithm + */ +typedef enum { + /** Recommended for most applications, well balanced between false positives and false negatives */ + MBL_MW_ACC_BMI160_STEP_COUNTER_MODE_NORMAL= 0, + /** Recommended for light weighted persons, gives few false negatives but eventually more false positives */ + MBL_MW_ACC_BMI160_STEP_COUNTER_MODE_SENSITIVE, + /** Gives few false positives but eventually more false negatives */ + MBL_MW_ACC_BMI160_STEP_COUNTER_MODE_ROBUST +} MblMwAccBmi160StepCounterMode; + +/** + * Calculation modes controlling the conditions that determine the sensor's orientation + * @author Eric Tsai + */ +typedef enum { + /** Default mode */ + MBL_MW_ACC_BOSCH_ORIENTATION_MODE_SYMMETRICAL, + MBL_MW_ACC_BOSCH_ORIENTATION_MODE_HIGH_ASYMMETRICAL, + MBL_MW_ACC_BOSCH_ORIENTATION_MODE_LOW_ASYMMETRICAL +} MblMwAccBoschOrientationMode; + +/** + * Available quiet times for tap detection + * @author Eric Tsai + */ +typedef enum { + MBL_MW_ACC_BOSCH_TAP_QUIET_TIME_30ms= 0, + MBL_MW_ACC_BOSCH_TAP_QUIET_TIME_20ms +} MblMwAccBoschTapQuietTime; +/** + * Available shock times for tap detection + * @author Eric Tsai + */ +typedef enum { + MBL_MW_ACC_BOSCH_TAP_SHOCK_TIME_50ms= 0, + MBL_MW_ACC_BOSCH_TAP_SHOCK_TIME_75ms +} MblMwAccBoschTapShockTime; +/** + * Available windows for double tap detection + */ +typedef enum { + MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_50ms= 0, + MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_100ms, + MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_150ms, + MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_200ms, + MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_250ms, + MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_375ms, + MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_500ms, + MBL_MW_ACC_BOSCH_DOUBLE_TAP_WINDOW_700ms +} MblMwAccBoschDoubleTapWindow; + +/** + * Available windows for double tap detection + */ +typedef enum { + MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_XYZ= 0, + MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_YZX, + MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_ZXY, + MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_XZY, + MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_YXZ, + MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_ZYX +} MblMwAccBoschAxisXyzRemap; + +/** + * Available windows for double tap detection + */ +typedef enum { + MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_000= 0, + MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_100, + MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_110, + MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_101, + MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_010, + MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_011, + MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_001, + MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_111 +} MblMwAccBoschAxisXyzSign; + +/** + * Wrapper class encapsulating responses from any motion detection + */ +typedef struct { + uint8_t sign; ///< Slope sign of the triggering motion, 0 if negative, non-zero if positive + uint8_t x_axis_active; ///< Non-zero if x-axis triggered the motion interrupt + uint8_t y_axis_active; ///< Non-zero if y-axis triggered the motion interrupt + uint8_t z_axis_active; ///< Non-zero if z-axis triggered the motion interrupt +} MblMwBoschAnyMotion; + +/** + * Wrapper class encapsulating responses from any motion detection + */ +typedef struct { + uint8_t type; ///< Slope sign of the triggering motion, 0 if negative, non-zero if positive + uint8_t gesture_code; ///< Non-zero if x-axis triggered the motion interrupt +} MblMwBoschGestureType; + +/** + * Retrieves the data signal representing acceleration data from a Bosch accelerometer + * This signal is timestamp,x,y,z acc data + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI160 acceleration data signal + * MblMwCartesianFloat is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bosch_get_acceleration_data_signal(const MblMwMetaWearBoard* board); +/** + * @deprecated As of v0.8.0 and will be removed in v1.0.0. Use mbl_mw_acc_bosch_get_packed_acceleration_data_signal instead. + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bosch_get_high_freq_acceleration_data_signal(const MblMwMetaWearBoard* board); +/** + * Variant of acceleration data that packs multiple data samples into 1 BLE packet to increase the + * data throughput. This data signal cannot be used with data processing or logging, only with streaming. + * This signal is timestamp,x,y,z,x,y,z,x,y,z acc data (it packs three acc data points in one timestamp) + * @return Pointer to the data signal + * [MblMwCartesianFloat, MblMwCartesianFloat, MblMwCartesianFloat] is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bosch_get_packed_acceleration_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the BMI160 step counter + * This signal represents the number of steps a user has taken + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI160 step counter data signal + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bmi160_get_step_counter_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the BMI270 step counter + * This signal represents the number of steps a user has taken + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI270 step counter data signal + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bmi270_get_step_counter_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the BMI160 step detector + * This signal simply detects a step, it does not count it + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI160 step detector data signal + * No return data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bmi160_get_step_detector_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the BMI270 step detector + * This signal simply detects a step, it does not count it + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI270 step detector data signal + * No return data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bmi270_get_step_detector_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the wrist gesture algorithm + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI270 step detector data signal + * UINT32 is return signal data type represented by MblMwAccGestureCode + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bmi270_get_wrist_detector_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the activity detection algorithm + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI270 step detector data signal + * UINT32 is return signal data type represented by MblMwAccActivityCode + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bmi270_get_activity_detector_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the orientation detection algorithm + * This signal is identical to smartphone orientation (portrait, landscape) + * The BMI270 does not support this function. + * @param board Calling object + * @return Pointer to Bosch's orientation detection data signal + * MblMwSensorOrientation is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bosch_get_orientation_detection_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the motion detection algorithm + * This signal retrieves either "no motion", "any motion" or "significant motion" depending on user settings + * @param board Calling object + * @return Pointer to Bosch's motion detection data signal + * UINT32 is return signal data type represented by MblMwAccMotionTypes + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bosch_get_motion_data_signal(const MblMwMetaWearBoard* board); +/** + * Retrieves the data signal representing data from the tap detection algorithm + * This signal retrieves the number of taps the board has been subjected to based on user settings + * The BMI270 does not support this function. + * @param board Calling object + * @return Pointer to Bosch's tap detection data signal + * MblMwBoschTap is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_bosch_get_tap_data_signal(const MblMwMetaWearBoard* board); +/** + * Sets the output data rate for the BMI160 accelerometer + * The ODR sets the output data frequency in Hz. + * See MblMwAccBmi160Odr for allowed values. + * @param board Pointer to the board to modify + * @param odr Output data rate value to assign + */ +METAWEAR_API void mbl_mw_acc_bmi160_set_odr(MblMwMetaWearBoard *board, MblMwAccBmi160Odr odr); +/** + * Sets the output data rate for the BMI160 accelerometer + * The ODR sets the output data frequency in Hz. + * See MblMwAccBmi160Odr for allowed values. + * @param board Pointer to the board to modify + * @param odr Output data rate value to assign + */ +METAWEAR_API void mbl_mw_acc_bmi270_set_odr(MblMwMetaWearBoard *board, MblMwAccBmi270Odr odr); +/** + * Sets the output data rate for the BMI160 accelerometer + * The ODR sets the output data frequency in Hz. + * See MblMwAccBmi160Odr for allowed values. + * @param board Pointer to the board to modify + * @param odr Output data rate value to assign + */ +METAWEAR_API void mbl_mw_acc_bma255_set_odr(MblMwMetaWearBoard *board, MblMwAccBma255Odr odr); +/** + * Sets the acceleration range + * The range is in units of Gs between 2 and 16gs for Bosch sensors + * See MblMwAccBoschRange for allowed values. + * @param board Pointer to the board to modify + * @param range Acceleration range to assign + */ +METAWEAR_API void mbl_mw_acc_bosch_set_range(MblMwMetaWearBoard *board, MblMwAccBoschRange range); +/** + * Writes the acceleration settings to the sensor + * Applies the ODR and RANGE values set in set_range() and set_odr(). + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bosch_write_acceleration_config(const MblMwMetaWearBoard *board); +/** + * Sets the operational mode of the step counter + * - Normal mode (default setting, recommended for most applications) + * - Sensitive mode (can be used for light weighted, small persons) + * - Robust mode (can be used, if many false positive detections are observed) + * @param board Board to modify + * @param mode New operation mode + */ +METAWEAR_API void mbl_mw_acc_bmi160_set_step_counter_mode(MblMwMetaWearBoard* board, MblMwAccBmi160StepCounterMode mode); +/** + * Enables the BMI160 step counter + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_acc_bmi160_enable_step_counter(MblMwMetaWearBoard* board); +/** + * Disables the BMI160 step counter + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_acc_bmi160_disable_step_counter(MblMwMetaWearBoard* board); +/** + * Writes the step counter configuration to the sensor + * Applies the MODE set by set_step_counter_mode() + * @param board Board to write to + */ +METAWEAR_API void mbl_mw_acc_bmi160_write_step_counter_config(const MblMwMetaWearBoard *board); +/** + * Resets the BMI160 step counter (step counter = 0) + * Does not disable the step counter + * @param board Board to reset + */ +METAWEAR_API void mbl_mw_acc_bmi160_reset_step_counter(const MblMwMetaWearBoard *board); +/** + * Enables the BMI160 step detector + * A callback will notify the user when a step is detected but will NOT count steps + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bmi160_enable_step_detector(const MblMwMetaWearBoard *board); +/** + * Disables the BMI160 step detector + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bmi160_disable_step_detector(const MblMwMetaWearBoard *board); +/** + * Writes the step counter configuration to the sensor + * Applies the MODE set by set_step_counter_mode() + * @param board Board to write to + */ +METAWEAR_API void mbl_mw_acc_bmi160_write_step_counter_config(const MblMwMetaWearBoard *board); +/** + * Sets the watermark level of the step counter + * The Step-counter will trigger output every time this number of steps are counted. + * Holds implicitly a 20x factor, so the range is 0 to 20460, with resolution of 20 steps. + * If 0, the output is disabled. If 1, it will count to 20 steps. + * @param board Board to modify + * @param trigger Number of steps + */ +METAWEAR_API void mbl_mw_acc_bmi270_set_step_counter_trigger(MblMwMetaWearBoard* board, uint16_t trigger); +/** + * Enables the BMI270 step counter + * The trigger count will trigger the callback signal with the # of steps + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_acc_bmi270_enable_step_counter(const MblMwMetaWearBoard *board); +/** + * Disables the BMI270 step counter + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_acc_bmi270_disable_step_counter(const MblMwMetaWearBoard *board); +/** + * Writes the step counter configuration to the sensor + * Applies the TRIGGER set by set_step_counter_trigger() + * @param board Board to write to + */ +METAWEAR_API void mbl_mw_acc_bmi270_write_step_counter_config(const MblMwMetaWearBoard *board); +/** + * Resets the BMI270 step counter (step counter = 0) + * Does not disable the step counter + * @param board Board to reset + */ +METAWEAR_API void mbl_mw_acc_bmi270_reset_step_counter(const MblMwMetaWearBoard *board); +/** + * Reads the current step count. The callback function will be called with: + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param handler Callback function that is executed when the task is finished + */ +METAWEAR_API void mbl_mw_acc_bmi270_read_step_counter(MblMwMetaWearBoard* board, void* context, MblMwFnBoardPtrInt handler); +/** + * Sets the arm side the MetaWear is worn on for gesture recognition + * Device in left (0 - false) or right (1 - true) arm. + * By default, the wearable device is assumed to be in left arm i.e. default value is 0 - false. + * @param board Pointer to the board to send the command to + * @param side 1 = Right arm, 0 = Left arm + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_gesture_armside(const MblMwMetaWearBoard *board, uint8_t side); +/** + * Sets the tilt angle for gesture recognition + * Sine of the minimum tilt angle in portrait down direction of the device when wrist is rolled away (roll-out) from user. + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). + * Range is 1448 to 1774. Default value is 1774. + * @param board Pointer to the board to send the command to + * @param peak Tilt Angle + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_gesture_peak(const MblMwMetaWearBoard* board, uint16_t peak); +/** + * Value of minimum time difference between wrist roll-out and roll-in movement during flick gesture. + * Range is 3 to 5 samples at 50Hz (i.e. 0.06 to 0.1 seconds). Default value is 4 (i.e. 0.08 seconds). + * @param board Pointer to the board to send the command to + * @param sample + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_gesture_samples(const MblMwMetaWearBoard* board, uint16_t samples); +/** + * Sets the maximum time for the gesture recognition + * Maximum time within which gesture movement has to be completed. + * Range is 150 to 250 samples at 50Hz (i.e. 3 to 5 seconds). Defualt value is 200 (i.e. 4 seconds). + * @param board Pointer to the board to send the command to + * @param duration + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_gesture_duration(const MblMwMetaWearBoard* board, uint16_t duration); +/** + * Writes the wrist gesture recognition configuration to the sensor + * Applies the ARM SIDE, PEAK, SAMPLE and DURATION set by set_wrist_gesture_*() + * @param board Board to write to + */ +METAWEAR_API void mbl_mw_acc_bmi270_write_wrist_gesture_config(const MblMwMetaWearBoard* board); +/** + * Enables the BMI270 wrist gesture recognition + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_acc_bmi270_enable_wrist_gesture(const MblMwMetaWearBoard* board); +/** + * Disables the BMI270 wrist gesture recognition + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_acc_bmi270_disable_wrist_gesture(const MblMwMetaWearBoard* board); +/** + * Sets the minimum angle change for wrist wakeup + * Cosine of minimum expected attitude change of the device within 1 second time window when moving within focus position. + * The parameter is scaled by 2048 i.e. 2048 * cos(angle). Range is 1024 to 1774. Default is 1448. + * @param board Pointer to the board to send the command to + * @param angle Minimum angle + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_wakeup_angle_focus(const MblMwMetaWearBoard* board, uint16_t angle); +/** + * Sets the maximum angle change for wrist wakeup + * Cosine of minimum expected attitude change of the device within 1 second time window when moving from non-focus to focus position. + * The parameter is scaled by 2048 i.e. 2048 * cos(angle). Range is 1448 to 1856. Default value is 1774. + * @param board Pointer to the board to send the command to + * @param angle Maximum angle + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_wakeup_angle_nonfocus(const MblMwMetaWearBoard* board, uint16_t angle); +/** + * Sets the + * Sine of the maximum allowed downward tilt angle in landscape right direction of the device, when it is in focus position. + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). Range is 700 to 1024. Default value is 1024. + * @param board Pointer to the board to send the command to + * @param angle Maximum tilt angle in Landscape Right mode + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_wakeup_tilt_lr(const MblMwMetaWearBoard* board, uint16_t angle); +/** + * Sets the + * Sine of the maximum allowed downward tilt angle in landscape left direction of the device, when it is in focus position. + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). Range is 700 to 1024. Default value is 700. + * @param board Pointer to the board to send the command to + * @param angle Maximum tilt angle in Landscape Left mode + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_wakeup_tilt_ll(const MblMwMetaWearBoard* board, uint16_t angle); +/** + * Sets the + * Sine of the maximum allowed backward tilt angle in portrait down direction of the device, when it is in focus position. + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). Range is 0 to179. Default value is 179. + * @param board Pointer to the board to send the command to + * @param angle Maximum tilt angle in Portrait Down mode + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_wakeup_tilt_pd(const MblMwMetaWearBoard* board, uint16_t angle); +/** + * Sets the + * Sine of the maximum allowed forward tilt angle in portrait up direction of the device, when it is in focus position. + * The configuration parameter is scaled by 2048 i.e. 2048 * sin(angle). Range is 1774 to 1978. Default value is 1925. + * @param board Pointer to the board to send the command to + * @param angle Maximum tilt angle in Portrait Up mode + */ +METAWEAR_API void mbl_mw_acc_bmi270_wrist_wakeup_tilt_pu(const MblMwMetaWearBoard* board, uint16_t angle); +/** + * Writes the wrist gesture recognition configuration to the sensor + * Applies the ARM SIDE, PEAK, SAMPLE and DURATION set by set_wrist_gesture_*() + * @param board Board to write to + */ +METAWEAR_API void mbl_mw_acc_bmi270_write_wrist_wakeup_config(const MblMwMetaWearBoard* board); +/** + * Enables the BMI270 wrist wakeup recognition + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_acc_bmi270_enable_wrist_wakeup(const MblMwMetaWearBoard* board); +/** + * Disables the BMI270 wrist wakeup recognition + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_acc_bmi270_disable_wrist_wakeup(const MblMwMetaWearBoard* board); +/** + * Enables the BMI270 activity detector + * A callback will notify the user when an activity is detected (walking, running, still) + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bmi270_enable_activity_detection(const MblMwMetaWearBoard *board); +/** + * Disables the BMI270 activity detector + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bmi270_disable_activity_detection(const MblMwMetaWearBoard *board); +/** + * Enables the BMI270 step detector + * A callback will notify the user when a step is detected but will NOT count steps + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bmi270_enable_step_detector(const MblMwMetaWearBoard *board); +/** + * Disables the BMI270 step detector + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bmi270_disable_step_detector(const MblMwMetaWearBoard *board); +/** + * Downsampling for the BMI270 acc + * See BMI270 datasheet for more details + * @param board Pointer to the board to send the command to + * @param gyro_downs Downsampling for Gyroscope (2**downs_gyro) + * @param gyro_data Selects filtered or unfiltered Gyroscope data for fifo + * @param acc_downs Downsampling for Accelerometer (2**downs_accel) + * @param acc_data Selects filtered or unfiltered Accelerometer data for fifo + */ +METAWEAR_API void mbl_mw_acc_bmi270_fifo_downs(const MblMwMetaWearBoard* board, uint8_t gyro_downs, uint8_t gyro_data, uint8_t acc_downs, uint8_t acc_data); +/** + * Manual compensation for the BMI270 acc + * The offset compensation registers have a width of 8 bit using two’s complement notation. + * The offset resolution (LSB) is 3.9 mg and the offset range is +- 0.5 g + * @param board Pointer to the board to send the command to + * @param x_offset Offset compensation for Accelerometer X-axis + * @param y_offset Offset compensation for Accelerometer Y-axis + * @param z_offset Offset compensation for Accelerometer Z-axis + */ +METAWEAR_API void mbl_mw_acc_bmi270_acc_offsets(const MblMwMetaWearBoard* board, uint16_t x_offset, uint16_t y_offset, uint16_t z_offset); +/** + * Remaps the BMI270 axis + * If the coordinate system of the MetaWear differs from the sensor coordinate system described in the BMI270 datasheet, + * the sensor axis must be remapped to use the orientation dependent features properly. + * Axis remapping register allows the host to freely map individual axis to the coordinate system of the used platform. + * Individual axis can be mapped to any other defined axis. The sign value of the axis can be also configured. + * @param board Pointer to the board to send the command to + * @param map X,Y,Z axis remap + * @param sign X,Y,Z axis flip/sign + */ +METAWEAR_API void mbl_mw_acc_bmi270_axis_remap(const MblMwMetaWearBoard *board, MblMwAccBoschAxisXyzRemap map, MblMwAccBoschAxisXyzSign sign); +/** + * Set the hysteresis offset (degrees) for portrait/landscape detection + * Upside/downside recognition hysteresis is not configurable. + * See the BMI160 datasheet for more information. + * Not supported by the BMI270. + * @param board Calling object + * @param hysteresis New calculation mode + */ +METAWEAR_API void mbl_mw_acc_bosch_set_orientation_hysteresis(MblMwMetaWearBoard *board, float hysteresis); +/** + * Set the orientation calculation mode + * Options include: Symmetrical, High asymmetrical, Low asymmetrical + * See the BMI160 datasheet for more information. + * Not supported by the BMI270. + * @param board Calling object + * @param mode New calculation mode + */ +METAWEAR_API void mbl_mw_acc_bosch_set_orientation_mode(MblMwMetaWearBoard *board, MblMwAccBoschOrientationMode mode); +/** + * Writes the orientation detection settings to the board + * Applies MODE and HYSTERESIS from set_orientation_hysteresis() and set_orientation_mode() + * Not supported by the BMI270. + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_bosch_write_orientation_config(const MblMwMetaWearBoard *board); +/** + * Enables orientation detection + * Not supported by the BMI270. + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_bosch_enable_orientation_detection(const MblMwMetaWearBoard *board); +/** + * Disables orientation detection + * Not supported by the BMI270. + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_bosch_disable_orientation_detection(const MblMwMetaWearBoard *board); +/** + * Sets the tap detector's quiet time parameter + * Selects a tap quiet duration of ‘0’->30 ms, ‘1’->20 ms (i.e how long to wait for another tap) + * The criteria for a double-tap are fulfilled if the second tap occurs after the time quiet time and within the tap window. + * If during the quiet time period (30/20ms) a tap occurs, it will be considered as a new tap. + * Not supported by the BMI270. + * @param board Calling object + * @param time New quiet time + */ +METAWEAR_API void mbl_mw_acc_bosch_set_quiet_time(MblMwMetaWearBoard *board, MblMwAccBoschTapQuietTime time); +/** + * Sets the tap detector's shock time parameter + * Selects a tap shock duration of ‘0’->50ms, ‘1’->75ms (i.e how long a tap can be) + * This is the time it take the tap to "settle". + * Not supported by the BMI270. + * @param board Calling object + * @param time New shock time + */ +METAWEAR_API void mbl_mw_acc_bosch_set_shock_time(MblMwMetaWearBoard *board, MblMwAccBoschTapShockTime time); +/** + * Sets the tap detector's double tap window + * The time window between two taps is between 12.5ms and 500ms. + * The criteria for a double-tap are fulfilled if the second tap occurs after the quiet time and within the tap window. + * Not supported by the BMI270. + * @param board Calling object + * @param window New double tap window time + */ +METAWEAR_API void mbl_mw_acc_bosch_set_double_tap_window(MblMwMetaWearBoard *board, MblMwAccBoschDoubleTapWindow window); +/** + * Sets the tap detector's threshold + * Threshold of the single/double-tap interrupt corresponding to an acceleration difference. + * The threshold is typically between 0.7g and 1.5g in 2g measurement range. + * Not supported by the BMI270. + * @param board Calling object + * @param window New threshold level + */ +METAWEAR_API void mbl_mw_acc_bosch_set_threshold(MblMwMetaWearBoard *board, float threshold); +/** + * Sets the tap detector's double tap window + * Applies the duration, quiet window, shock, and threshold from set_threshold(), set_double_tap_window(), set_shock_time(), set_quiet_time(). + * Not supported by the BMI270. + * @param board Calling object + * @param window New double tap window time + */ +METAWEAR_API void mbl_mw_acc_bosch_write_tap_config(const MblMwMetaWearBoard *board); +/** + * Enables the tap detector + * Not supported by the BMI270. + * @param board Calling object + * @param enable_single 0 to ignore single tap detection, non-zero to detect + * @param enable_double 0 to ignore double tap detection, non-zero to detect + */ +METAWEAR_API void mbl_mw_acc_bosch_enable_tap_detection(const MblMwMetaWearBoard *board, uint8_t enable_single, uint8_t enable_double); +/** + * Disable the tap detector + * Not supported by the BMI270. + * @param board Calling object + * @param window New double tap window time + */ +METAWEAR_API void mbl_mw_acc_bosch_disable_tap_detection(const MblMwMetaWearBoard *board); +/** + * Sets the any motion detector's count parameter + * Any-motion generates an interrupt when the absolute value of the acceleration exceeds a "threshold" + * for a certain "count" of consecutive data points. + * For the BMI160, it is a simple counter. + * For the BMI270, it is expressed in 50 Hz samples (20 ms). Range is 0 to 163sec. Default value is 5=100ms. + * @param board Calling object + * @param count Number of consecutive slope data points that must be above the threshold + */ +METAWEAR_API void mbl_mw_acc_bosch_set_any_motion_count(MblMwMetaWearBoard *board, uint8_t count); +/** + * Sets the any motion detector's threshold parameter + * Any-motion generates an interrupt when the absolute value of the acceleration exceeds a "threshold" + * for a certain "count" of consecutive data points. + * For the BMI160, it is range-dependent (see datasheet). Default value is 0x14 = 5.11mg in 2g mode. + * For the BMI270, range is 0 to 1g. Default value is 0xAA = 83mg. + * @param board Calling object + * @param threshold Value that the slope data points must be above + */ +METAWEAR_API void mbl_mw_acc_bosch_set_any_motion_threshold(MblMwMetaWearBoard *board, float threshold); +/** + * Sets the no motion detector's count parameter + * @param board Calling object + * @param count Number of consecutive slope data points that must be above the threshold + */ +METAWEAR_API void mbl_mw_acc_bosch_set_no_motion_count(MblMwMetaWearBoard *board, uint8_t count); +/** + * Sets the no motion detector's threshold parameter + * @param board Calling object + * @param threshold Value that the slope data points must be above + */ +METAWEAR_API void mbl_mw_acc_bosch_set_no_motion_threshold(MblMwMetaWearBoard *board, float threshold); +/** + * Sets the sig motion detector's blocksize parameter + * @param board Calling object + * @param threshold Value that the slope data points must be above + */ +METAWEAR_API void mbl_mw_acc_bosch_set_sig_motion_blocksize(MblMwMetaWearBoard *board, uint16_t blocksize); +/** + * Writes the motion configuration to the remote device + * Applies the threshold and count parameter or blocksize depending on motion type and settings from set_*_*() + * For the BMI270, types include no motion, significant motion, and any motion. + * Ignored for other Bosch sensors. + * @param board Calling object + * @param type Type of motion requested + */ +METAWEAR_API void mbl_mw_acc_bosch_write_motion_config(const MblMwMetaWearBoard *board, MblMwAccBoschMotion type); +/** + * Enables motion detection + * The signal will callback if any motion is sensed based on the motion config + * For the BMI270, signals include no motion, significant motion, and any motion. + * Ignored for other Bosch sensors. + * @param board Calling object + * @param type Type of motion requested + */ +METAWEAR_API void mbl_mw_acc_bosch_enable_motion_detection(const MblMwMetaWearBoard *board, MblMwAccBoschMotion type); +/** + * Disables motion detection + * @param board Calling object + * @param type Type of motion requested + */ +METAWEAR_API void mbl_mw_acc_bosch_disable_motion_detection(const MblMwMetaWearBoard *board, MblMwAccBoschMotion type); +/** + * Switches the accelerometer to active mode + * When in active mode, the accelerometer cannot be configured. + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bosch_start(const MblMwMetaWearBoard *board); +/** + * Switches the accelerometer to standby mode (low power state) + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bosch_stop(const MblMwMetaWearBoard *board); +/** + * Enables acceleration sampling + * The board will start gathering data from the accelerometer + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bosch_enable_acceleration_sampling(const MblMwMetaWearBoard *board); +/** + * Disables acceleration sampling + * The board will stop gathering data from the accelerometer + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_acc_bosch_disable_acceleration_sampling(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer_mma8452q.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer_mma8452q.h new file mode 100644 index 0000000..c658903 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/accelerometer_mma8452q.h @@ -0,0 +1,162 @@ +/** + * @copyright MbientLab License + * @file accelerometer_mma8452q.h + * @brief Functions for interacting with the MMA8452Q accelerometer. + * @details This sensor is only available on MetaWear R boards. + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* +typedef enum { + MBL_MW_ACC_MMA8452Q_AXIS_X, + MBL_MW_ACC_MMA8452Q_AXIS_Y, + MBL_MW_ACC_MMA8452Q_AXIS_Z +} MblMWMma8452qAxis; + +typedef enum { + MBL_MW_ACC_MMA8452Q_FREE_FALL, + MBL_MW_ACC_MMA8452Q_MOTION +} MblMwAccMma8452qMovementType; +*/ + +/** + * Available g-ranges on the MMA8452Q accelerometer + */ +typedef enum { + MBL_MW_ACC_MMA8452Q_RANGE_2G= 0, ///< +/- 2g + MBL_MW_ACC_MMA8452Q_RANGE_4G, ///< +/- 4g + MBL_MW_ACC_MMA8452Q_RANGE_8G ///< +/- 8g +} MblMwAccMma8452qRange; + +/** + * Available output data rates on the MMA8452Q accelerometer + */ +typedef enum { + MBL_MW_ACC_MMA8452Q_ODR_800Hz= 0, + MBL_MW_ACC_MMA8452Q_ODR_400Hz, + MBL_MW_ACC_MMA8452Q_ODR_200Hz, + MBL_MW_ACC_MMA8452Q_ODR_100Hz, + MBL_MW_ACC_MMA8452Q_ODR_50Hz, + MBL_MW_ACC_MMA8452Q_ODR_12_5Hz, + MBL_MW_ACC_MMA8452Q_ODR_6_25Hz, + MBL_MW_ACC_MMA8452Q_ODR_1_56Hz +} MblMwAccMma8452qOdr; + +/** + * Available cutoff frequencies for the MMA8452Q high pass filter + */ +typedef enum { + MBL_MW_ACC_MMA8452Q_CUTOFF_FREQ_HIGHEST = 0, + MBL_MW_ACC_MMA8452Q_CUTOFF_FREQ_HIGH = 1, + MBL_MW_ACC_MMA8452Q_CUTOFF_FREQ_MEDIUM = 2, + MBL_MW_ACC_MMA8452Q_CUTOFF_FREQ_LOW = 3 +} MblMwAccMma8452qCutoffFreq; + +/** + * Retrieves the data signal representing acceleration data for the MMA8452Q accelerometer + * This signal is timestamp,x,y,z acc data + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's MMA8452Q acceleration data signal + * MblMwCartesianFloat is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_mma8452q_get_acceleration_data_signal(const MblMwMetaWearBoard *board); +/** + * @deprecated As of v0.8.0 and will be removed in v1.0.0. Use mbl_mw_acc_mma8452q_get_packed_acceleration_data_signal instead. + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_mma8452q_get_high_freq_acceleration_data_signal(const MblMwMetaWearBoard *board); +/** + * Variant of acceleration data that packs multiple data samples into 1 BLE packet to increase the + * data throughput. This data signal cannot be used with data processing or logging, only with streaming. + * This signal is timestamp,x,y,z,x,y,z,x,y,z acc data (it packs three acc data points in one timestamp) + * @return Pointer to the data singal + * [MblMwCartesianFloat, MblMwCartesianFloat, MblMwCartesianFloat] is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_mma8452q_get_packed_acceleration_data_signal(const MblMwMetaWearBoard *board); +/** + * Sets the output data rate + * The ODR sets the output data frequency in Hz. + * @param board Calling object + * @param odr Output data rate value to set + */ +METAWEAR_API void mbl_mw_acc_mma8452q_set_odr(MblMwMetaWearBoard *board, MblMwAccMma8452qOdr odr); +/** + * Sets the acceleration range + * The range is in units of Gs + * @param board Calling object + * @param range Acceleration range value to set + */ +METAWEAR_API void mbl_mw_acc_mma8452q_set_range(MblMwMetaWearBoard *board, MblMwAccMma8452qRange range); +/** + * Sets the cutoff frequency for the high-pass filter + * The high-pass filter cutoff frequency can be set by the user to four different frequencies which are dependent on the output data rate (ODR) + * Cutoff frequency is set to 16 Hz @ 800 Hz by default. See the MM8452Q datasheet for available options. + * @param board Calling object + * @param frequency Hpf cutoff frequency, set to 0 to disable the high pass filter + */ +METAWEAR_API void mbl_mw_acc_mma8452q_set_high_pass_cutoff(MblMwMetaWearBoard *board, float frequency); +/** + * Writes the acceleration settings to the sensor + * Applies the ODR and RANGE values set in set_range() and set_odr(). + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_mma8452q_write_acceleration_config(const MblMwMetaWearBoard *board); +/** + * Switches the accelerometer to active mode. + * When in active mode, the accelerometer cannot be configured + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_mma8452q_start(const MblMwMetaWearBoard *board); +/** + * Switches the accelerometer to standby mode + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_mma8452q_stop(const MblMwMetaWearBoard *board); +/** + * Enables acceleration sampling + * The board will start gathering data from the accelerometer + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_mma8452q_enable_acceleration_sampling(const MblMwMetaWearBoard *board); +/** + * Disables acceleration sampling + * The board will stop gathering data from the accelerometer + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_mma8452q_disable_acceleration_sampling(const MblMwMetaWearBoard *board); +/** + * Retrieves the data signal representing data from the orientation detection algorithm + * This signal is static orientation detection (portrait/landscape, up/down, left/right, back/front position) + * @param board Calling object + * @return Pointer to MMA8452Q's orientation detection data signal + * MblMwSensorOrientation is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_acc_mma8452q_get_orientation_detection_data_signal(const MblMwMetaWearBoard* board); +/** + * Set the orientation calculation mode + * @param board Calling object + * @param delay Time, in milliseconds, for which the sensor's orientation must remain in the new position + * before a position change is triggered + */ +METAWEAR_API void mbl_mw_acc_mma8452q_set_orientation_delay(MblMwMetaWearBoard *board, uint16_t delay); +/** + * Enables orientation detection + * The board will start gathering orientation data from the accelerometer + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_mma8452q_enable_orientation_detection(const MblMwMetaWearBoard *board); +/** + * Disables orientation detection + * The board will stop gathering orientation data from the accelerometer + * @param board Calling object + */ +METAWEAR_API void mbl_mw_acc_mma8452q_disable_orientation_detection(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/ambientlight_ltr329.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/ambientlight_ltr329.h new file mode 100644 index 0000000..733b2e9 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/ambientlight_ltr329.h @@ -0,0 +1,104 @@ +/** + * @copyright MbientLab License + * @file ambientlight_ltr329.h + * @brief Functions for interacting with the LTR329 ambient light sensor. + * @details This sensor is only available on MetaWear RPro boards. + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Controls the range and resolution of illuminance values + */ +typedef enum { + MBL_MW_ALS_LTR329_GAIN_1X= 0, ///< Illuminance range between [1, 64k] lux (default) + MBL_MW_ALS_LTR329_GAIN_2X, ///< Illuminance range between [0.5, 32k] lux + MBL_MW_ALS_LTR329_GAIN_4X, ///< Illuminance range between [0.25, 16k] lux + MBL_MW_ALS_LTR329_GAIN_8X, ///< Illuminance range between [0.125, 8k] lux + MBL_MW_ALS_LTR329_GAIN_48X, ///< Illuminance range between [0.02, 1.3k] lux + MBL_MW_ALS_LTR329_GAIN_96X ///< Illuminance range between [0.01, 600] lux +} MblMwAlsLtr329Gain; + +/** + * Measurement time for each cycle + */ +typedef enum { + MBL_MW_ALS_LTR329_TIME_100ms= 0, ///< Default setting + MBL_MW_ALS_LTR329_TIME_50ms, + MBL_MW_ALS_LTR329_TIME_200ms, + MBL_MW_ALS_LTR329_TIME_400ms, + MBL_MW_ALS_LTR329_TIME_150ms, + MBL_MW_ALS_LTR329_TIME_250ms, + MBL_MW_ALS_LTR329_TIME_300ms, + MBL_MW_ALS_LTR329_TIME_350ms +} MblMwAlsLtr329IntegrationTime; + +/** + * How frequently to update the illuminance data. + */ +typedef enum { + MBL_MW_ALS_LTR329_RATE_50ms= 0, + MBL_MW_ALS_LTR329_RATE_100ms, + MBL_MW_ALS_LTR329_RATE_200ms, + MBL_MW_ALS_LTR329_RATE_500ms, ///< Default setting + MBL_MW_ALS_LTR329_RATE_1000ms, + MBL_MW_ALS_LTR329_RATE_2000ms +} MblMwAlsLtr329MeasurementRate; + +/** + * Retrieves the data signal representing LTR329 illuminance data + * This signal represents the luminance in lux + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's LTR329 illuminance data signal + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_als_ltr329_get_illuminance_data_signal(const MblMwMetaWearBoard *board); +/** + * Sets the sensor gain + * There are altogether six gain settings (1X, 2X, 4X, 8X, 48X and 96X) available for user to configure + * See MblMwAlsLtr329Gain for allowed values + * @param board Pointer to the board to modify + * @param gain Sensor gain value to set + */ +METAWEAR_API void mbl_mw_als_ltr329_set_gain(MblMwMetaWearBoard *board, MblMwAlsLtr329Gain gain); +/** + * Sets the sensor integration time + * Measurement time for each full light measurement (ALS) cycle - 100ms (default) to 350 ms + * See MblMwAlsLtr329IntegrationTime for allowed values + * @param board Pointer to the board to modify + * @param integration_time Integration time value to set + */ +METAWEAR_API void mbl_mw_als_ltr329_set_integration_time(MblMwMetaWearBoard *board, MblMwAlsLtr329IntegrationTime integration_time); +/** + * Sets the sensor measurement rate + * Frequency of light measurement - 50ms (default) to 2000 ms + * See MblMwAlsLtr329MeasurementRate for allowed values + * @param board Pointer to the board to modify + * @param measurement_rate Measurement rate value to set + */ +METAWEAR_API void mbl_mw_als_ltr329_set_measurement_rate(MblMwMetaWearBoard *board, MblMwAlsLtr329MeasurementRate measurement_rate); +/** + * Writes the configuration to the LTR329 sensor + * Applies the INTEGRATION TIME, MEASUREMENT RATE, and GAIN values set in set_*(). + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_als_ltr329_write_config(const MblMwMetaWearBoard *board); +/** + * Starts illuminance sampling + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_als_ltr329_start(const MblMwMetaWearBoard *board); +/** + * Stops illuminance sampling + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_als_ltr329_stop(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/barometer_bosch.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/barometer_bosch.h new file mode 100644 index 0000000..bf2e88e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/barometer_bosch.h @@ -0,0 +1,153 @@ +/** + * @copyright MbientLab License + * @file barometer_bosch.h + * @brief Interacts with the supported Bosch barometers, currenly BMP280 and BME280 + * @details The BMP280 and BME280 sensors are identical except for the standby times. Functions that are generic for + * both barometers have "bosch" in the name whereas functions specific to either accelerometer are contain their model + * i.e. "bmp280" or "bme280". + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Supported oversampling modes on the Bosch barometers + */ +typedef enum { + MBL_MW_BARO_BOSCH_OVERSAMPLING_SKIP= 0, + MBL_MW_BARO_BOSCH_OVERSAMPLING_ULTRA_LOW_POWER, + MBL_MW_BARO_BOSCH_OVERSAMPLING_LOW_POWER, + MBL_MW_BARO_BOSCH_OVERSAMPLING_STANDARD, + MBL_MW_BARO_BOSCH_OVERSAMPLING_HIGH, + MBL_MW_BARO_BOSCH_OVERSAMPLING_ULTRA_HIGH +} MblMwBaroBoschOversampling; + +/** + * Supported filter modes on the Bosch barometers + */ +typedef enum { + MBL_MW_BARO_BOSCH_IIR_FILTER_OFF= 0, + MBL_MW_BARO_BOSCH_IIR_FILTER_AVG_2, + MBL_MW_BARO_BOSCH_IIR_FILTER_AVG_4, + MBL_MW_BARO_BOSCH_IIR_FILTER_AVG_8, + MBL_MW_BARO_BOSCH_IIR_FILTER_AVG_16 +} MblMwBaroBoschIirFilter; + +/** + * Supported stand by times on the BMP280 barometer + */ +typedef enum { + MBL_MW_BARO_BMP280_STANDBY_TIME_0_5ms= 0, + MBL_MW_BARO_BMP280_STANDBY_TIME_62_5ms, + MBL_MW_BARO_BMP280_STANDBY_TIME_125ms, + MBL_MW_BARO_BMP280_STANDBY_TIME_250ms, + MBL_MW_BARO_BMP280_STANDBY_TIME_500ms, + MBL_MW_BARO_BMP280_STANDBY_TIME_1000ms, + MBL_MW_BARO_BMP280_STANDBY_TIME_2000ms, + MBL_MW_BARO_BMP280_STANDBY_TIME_4000ms +} MblMwBaroBmp280StandbyTime; + +/** + * Supported stand by times on the BME280 barometer + */ +typedef enum { + MBL_MW_BARO_BME280_STANDBY_TIME_0_5ms= 0, + MBL_MW_BARO_BME280_STANDBY_TIME_62_5ms, + MBL_MW_BARO_BME280_STANDBY_TIME_125ms, + MBL_MW_BARO_BME280_STANDBY_TIME_250ms, + MBL_MW_BARO_BME280_STANDBY_TIME_500ms, + MBL_MW_BARO_BME280_STANDBY_TIME_1000ms, + MBL_MW_BARO_BME280_STANDBY_TIME_10ms, + MBL_MW_BARO_BME280_STANDBY_TIME_20ms +} MblMwBaroBme280StandbyTime; + +/** + * Retrieves the data signal representing pressure data from a Bosch barometer + * This signal represent the pressure in Pascals + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's pressure data signal + * uInt32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_baro_bosch_get_pressure_data_signal(const MblMwMetaWearBoard *board); +/** + * Retrieves the data signal representing a single read from a Bosch barometer + * This signal represent the pressure in Pascals + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's pressure data signal + * uInt32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_baro_bosch_get_pressure_read_data_signal(const MblMwMetaWearBoard *board); +/** + * Retrieves the data signal representing altitude data from a Bosch barometer + * This signal represent the altitude in Meters + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's altitude data signal + * Int32 is return signal data type (can be negative) + */ +METAWEAR_API MblMwDataSignal* mbl_mw_baro_bosch_get_altitude_data_signal(const MblMwMetaWearBoard *board); +/** + * Set the oversampling mode + * Settings available from ultra low power to ultra high resolution to adapt the sensor to the target application. + * See MblMwBaroBoschOversampling for allowed values. + * The settings are predefined combinations of pressure measurement oversampling and temperature measurement oversampling. + * @param board Pointer to the board to modify + * @param oversampling Oversampling value to set + */ +METAWEAR_API void mbl_mw_baro_bosch_set_oversampling(MblMwMetaWearBoard *board, MblMwBaroBoschOversampling oversampling); +/** + * Set the iir filter coefficient + * The built-in IIR filter minimizes short-term disturbances in the output data caused by the slamming of a door or window. + * The filter coefficient ranges from 0 (off) to 16. + * See MblMwBaroBoschIirFilter for allowed values. + * @param board Pointer to the board to modify + * @param iir_filter IIR filter value to set + */ +METAWEAR_API void mbl_mw_baro_bosch_set_iir_filter(MblMwMetaWearBoard *board, MblMwBaroBoschIirFilter iir_filter); +/** + * Set the standby time for the BMP280 barometer + * When the sensor operates in normal mode, it perpetualy cycles between an active measurement period and an inactive standby period. + * See MblMwBaroBmp280StandbyTime for allowed values. + * @param board Pointer to the board to modify + * @param standby_time Standby time value to set + */ +METAWEAR_API void mbl_mw_baro_bmp280_set_standby_time(MblMwMetaWearBoard *board, MblMwBaroBmp280StandbyTime standby_time); +/** + * Set the standby time for the BME280 barometer + * When the sensor operates in normal mode, it continuously cycles between an active measurement period and an inactive standby period. + * See MblMwBaroBme280StandbyTime for allowed values. + * @param board Pointer to the board to modify + * @param standby_time Standby time value to set + */ +METAWEAR_API void mbl_mw_baro_bme280_set_standby_time(MblMwMetaWearBoard *board, MblMwBaroBme280StandbyTime standby_time); +/** + * Set the standby time. If an invalid standby time is used, the closest valid value will be chosen + * When the sensor operates in normal mode, it continuously cycles between an active measurement period and an inactive standby period. + * @param board Pointer to the board to modify + * @param standby_time_ms Standby time value to set, in milliseconds + * @return Selected standby time, in milliseconds, or -1 if barometer not present + */ +METAWEAR_API float mbl_mw_baro_bosch_set_standby_time(MblMwMetaWearBoard *board, float standby_time_ms); +/** + * Writes the configuration to the sensor + * Applies the STANDBY, IIR and OVERSAMPLING values set in set_standbytime(), set_oversampling(), and set_iir_filter(). + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_baro_bosch_write_config(const MblMwMetaWearBoard *board); +/** + * Start pressure and altitude sensing + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_baro_bosch_start(const MblMwMetaWearBoard *board); +/** + * Stop pressure and altitude sensing + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_baro_bosch_stop(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/colordetector_tcs34725.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/colordetector_tcs34725.h new file mode 100644 index 0000000..14cd03e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/colordetector_tcs34725.h @@ -0,0 +1,74 @@ +/** + * @copyright MbientLab License (LICENSE.md) + * @file colordetector_tcs34725.h + * @brief Communicates with the TCS34725 color detector + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//@{ +/** Indices for component values of the color adc data signal, used with mbl_mw_datasignal_get_component */ +const uint8_t MBL_MW_CD_TCS34725_ADC_CLEAR_INDEX = 0, + MBL_MW_CD_TCS34725_ADC_RED_INDEX = 1, + MBL_MW_CD_TCS34725_ADC_GREEN_INDEX = 2, + MBL_MW_CD_TCS34725_ADC_BLUE_INDEX = 3; +//@} + +/** + * Available analog gain scale values + */ +typedef enum { + MBL_MW_CD_TCS34725_GAIN_1X= 0, + MBL_MW_CD_TCS34725_GAIN_4X, + MBL_MW_CD_TCS34725_GAIN_16X, + MBL_MW_CD_TCS34725_GAIN_60X +} MblMwColorDetectorTcs34725Gain; + +/** + * Retrieves the data signal representing detected ADC values for clear, red, green, and blue + * This signal represents the amount of each color present (C,R,G,B) as a percentage + * @param board Board the sensor resides on + * MblMwTcs34725ColorAdc is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_cd_tcs34725_get_adc_data_signal(const MblMwMetaWearBoard *board); +/** + * Sets the integration time - 2.4ms to 614.4ms in 2.4ms increments + * The RGBC integration time impacts both the resolution and the sensitivity of the RGBC reading. + * Integration of all four channels occurs simultaneously and upon completion of the conversion cycle, the results are transferred to the color data registers + * @param board Board to modify + * @param time New integration time to use, between [2.4, 614.4] milliseconds + */ +METAWEAR_API void mbl_mw_cd_tcs34725_set_integration_time(MblMwMetaWearBoard *board, float time); +/** + * Sets the analog gain scale + * RGBC gain control for the RGBC photodiodes - 1x, 4x, 16x, 60x + * See MblMwColorDetectorTcs34725Gain for allowed values. + * @param board Board to modify + * @param gain New gain scale to use + */ +METAWEAR_API void mbl_mw_cd_tcs34725_set_gain(MblMwMetaWearBoard *board, MblMwColorDetectorTcs34725Gain gain); +/** + * Writes the configuration to the sensor + * Applies the INTEGRATION TIME, and GAIN values set in set_*(). + * @param board Board the sensor resides on + */ +METAWEAR_API void mbl_mw_cd_tcs34725_write_config(const MblMwMetaWearBoard *board); +/** + * Enable the illuminator LED + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_cd_tcs34725_enable_illuminator_led(MblMwMetaWearBoard *board); +/** + * Disable the illuminator LED + * @param board Board to modify + */ +METAWEAR_API void mbl_mw_cd_tcs34725_disable_illuminator_led(MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/conductance.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/conductance.h new file mode 100644 index 0000000..342acd5 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/conductance.h @@ -0,0 +1,49 @@ +/** + * @copyright MbientLab License + * @file conductance.h + * @brief Interacts with conductance measurement sources. + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Enumeration of the available conductance measurment ranges + */ +typedef enum { + MBL_MW_CONDUCTANCE_RANGE_50uS= 0, + MBL_MW_CONDUCTANCE_RANGE_100uS, + MBL_MW_CONDUCTANCE_RANGE_150uS, + MBL_MW_CONDUCTANCE_RANGE_200uS, +} MblMwConductanceRange; + +/** + * Retrieves the data signal representing a conductance source + * @param board Board to retrieve the signal from + * @param channel Channel ID of the conductance source + */ +METAWEAR_API MblMwDataSignal* mbl_mw_conductance_get_data_signal(const MblMwMetaWearBoard *board, uint8_t channel); +/** + * Retrieve the number of available channels + * @return Number of channel IDs + */ +METAWEAR_API uint8_t mbl_mw_conductance_get_num_channels(const MblMwMetaWearBoard *board); +/** + * Trigger the automatic calibration routine. Fully self contained and requires no parameters. + * This should be called at least once after boot + */ +METAWEAR_API void mbl_mw_conductance_calibrate(const MblMwMetaWearBoard *board); +/** + * Sets the conductance measurment mode + * @param board Pointer to the board to modify + * @param range Range of the conductance values + */ +METAWEAR_API void mbl_mw_conductance_set_range(MblMwMetaWearBoard *board, MblMwConductanceRange range); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer.cpp new file mode 100644 index 0000000..1887383 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer.cpp @@ -0,0 +1,262 @@ +#include "metawear/sensor/accelerometer.h" +#include "metawear/sensor/accelerometer_bosch.h" +#include "metawear/sensor/accelerometer_mma8452q.h" +#include "accelerometer_private.h" +#include "accelerometer_bosch_private.h" +#include "accelerometer_mma8452q_private.h" +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/register.h" + +#include + +const float INVALID_SETTING= -1; + +using std::stringstream; +using std::vector; + +const uint8_t MBL_MW_MODULE_ACC_TYPE_MMA8452Q = 0; ///< Constant identifying the MMA8452Q accelerometer type +const uint8_t MBL_MW_MODULE_ACC_TYPE_BMI160 = 1; ///< Constant identifying the BMI160 accelerometer module type +const uint8_t MBL_MW_MODULE_ACC_TYPE_BMA255 = 3; ///< Constant identifying the BMA255 accelerometer module type +const uint8_t MBL_MW_MODULE_ACC_TYPE_BMI270 = 4; ///< Constant identifying the BMI270 accelerometer module type + +static const vector MMA8452Q_ODR_VALUES= {800.f, 400.f, 200.f, 100.f, 50.f, 12.5f, 6.25f, 1.56f}, + MMA8452Q_FSR_VALUES= {2.f, 4.f, 8.f}, + BMI270_ODR_VALUES= {0.78125f, 1.5625f, 3.125f, 6.25f, 12.5f, 25.f, 50.f, 100.f, 200.f, 400.f, 800.f, 1600.f}, + BMI160_ODR_VALUES= {0.78125f, 1.5625f, 3.125f, 6.25f, 12.5f, 25.f, 50.f, 100.f, 200.f, 400.f, 800.f, 1600.f}, + BMA255_ODR_VALUES= {15.62f, 31.26f, 62.5f, 125.f, 250.f, 500.f, 1000.f}, + BOSCH_FSR_VALUES= {2.f, 4.f, 8.f, 16.f}; + +void init_accelerometer_module(MblMwMetaWearBoard *board) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + init_accelerometer_mma8452q(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + init_accelerometer_bmi160(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMA255: + init_accelerometer_bma255(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI270: + init_accelerometer_bmi270(board); + break; + } +} + +void free_accelerometer_module(MblMwMetaWearBoard *board) { + if (!board->module_info.count(MBL_MW_MODULE_ACCELEROMETER)) { + return; + } + + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + free_accelerometer_mma8452q(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + free_accelerometer_bosch(board); + break; + } +} + +void serialize_accelerometer_config(const MblMwMetaWearBoard *board, std::vector& state) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + serialize_accelerometer_mma8452q_config(board, state); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + serialize_accelerometer_bmi160_config(board, state); + break; + case MBL_MW_MODULE_ACC_TYPE_BMA255: + serialize_accelerometer_bma255_config(board, state); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI270: + serialize_accelerometer_bmi270_config(board, state); + break; + } +} + +void deserialize_accelerometer_config(MblMwMetaWearBoard *board, uint8_t** state_stream) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + deserialize_accelerometer_mma8452q_config(board, state_stream); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + deserialize_accelerometer_bmi160_config(board, state_stream); + break; + case MBL_MW_MODULE_ACC_TYPE_BMA255: + deserialize_accelerometer_bma255_config(board, state_stream); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI270: + deserialize_accelerometer_bmi270_config(board, state_stream); + break; + } +} + +void create_acc_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(signal->owner->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + create_acc_mma8452q_uri(signal, uri); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + create_acc_bosch_uri(signal, uri); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI270: + create_acc_bmi270_uri(signal, uri); + break; + } +} + +MblMwDataSignal* mbl_mw_acc_get_acceleration_data_signal(const MblMwMetaWearBoard *board) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + return mbl_mw_acc_mma8452q_get_acceleration_data_signal(board); + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + return mbl_mw_acc_bosch_get_acceleration_data_signal(board); + } + return nullptr; +} + +MblMwDataSignal* mbl_mw_acc_get_high_freq_acceleration_data_signal(const MblMwMetaWearBoard *board) { + return mbl_mw_acc_get_packed_acceleration_data_signal(board); +} + +MblMwDataSignal* mbl_mw_acc_get_packed_acceleration_data_signal(const MblMwMetaWearBoard *board) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + return mbl_mw_acc_mma8452q_get_packed_acceleration_data_signal(board); + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + return mbl_mw_acc_bosch_get_packed_acceleration_data_signal(board); + } + return nullptr; +} + +float mbl_mw_acc_set_odr(MblMwMetaWearBoard *board, float odr) { + uint8_t index; + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + index= closest_index(MMA8452Q_ODR_VALUES, odr); + mbl_mw_acc_mma8452q_set_odr(board, (MblMwAccMma8452qOdr) index); + return MMA8452Q_ODR_VALUES[index]; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + index= closest_index(BMI160_ODR_VALUES, odr); + mbl_mw_acc_bmi160_set_odr(board, (MblMwAccBmi160Odr) index); + return BMI160_ODR_VALUES[index]; + case MBL_MW_MODULE_ACC_TYPE_BMA255: + index= closest_index(BMA255_ODR_VALUES, odr); + mbl_mw_acc_bma255_set_odr(board, (MblMwAccBma255Odr) index); + return BMA255_ODR_VALUES[index]; + case MBL_MW_MODULE_ACC_TYPE_BMI270: + index= closest_index(BMI270_ODR_VALUES, odr); + mbl_mw_acc_bmi270_set_odr(board, (MblMwAccBmi270Odr) index); + return BMI270_ODR_VALUES[index]; + } + + return INVALID_SETTING; +} + +float mbl_mw_acc_set_range(MblMwMetaWearBoard *board, float range) { + uint8_t index; + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + index= closest_index(MMA8452Q_FSR_VALUES, range); + mbl_mw_acc_mma8452q_set_range(board, (MblMwAccMma8452qRange) index); + return MMA8452Q_FSR_VALUES[index]; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + index= closest_index(BOSCH_FSR_VALUES, range); + mbl_mw_acc_bosch_set_range(board, (MblMwAccBoschRange) index); + return BOSCH_FSR_VALUES[index]; + } + + return INVALID_SETTING; +} + +void mbl_mw_acc_write_acceleration_config(const MblMwMetaWearBoard* board) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + mbl_mw_acc_mma8452q_write_acceleration_config(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + mbl_mw_acc_bosch_write_acceleration_config(board); + break; + } +} + +void mbl_mw_acc_read_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + read_accelerometer_mma8452q_acceleration_config(board, context, completed); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + read_accelerometer_bosch_acceleration_config(board, context, completed); + break; + } +} + +void mbl_mw_acc_start(const MblMwMetaWearBoard *board) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + mbl_mw_acc_mma8452q_start(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + mbl_mw_acc_bosch_start(board); + break; + } +} + +void mbl_mw_acc_stop(const MblMwMetaWearBoard *board) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + mbl_mw_acc_mma8452q_stop(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + mbl_mw_acc_bosch_stop(board); + break; + } +} + +void mbl_mw_acc_enable_acceleration_sampling(const MblMwMetaWearBoard *board) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + mbl_mw_acc_mma8452q_enable_acceleration_sampling(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + mbl_mw_acc_bosch_enable_acceleration_sampling(board); + break; + } +} + +void mbl_mw_acc_disable_acceleration_sampling(const MblMwMetaWearBoard *board) { + switch (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_MMA8452Q: + mbl_mw_acc_mma8452q_disable_acceleration_sampling(board); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: + case MBL_MW_MODULE_ACC_TYPE_BMI270: + mbl_mw_acc_bosch_disable_acceleration_sampling(board); + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch.cpp new file mode 100644 index 0000000..9eb0a90 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch.cpp @@ -0,0 +1,1642 @@ +#include "metawear/sensor/accelerometer_bosch.h" +#include "accelerometer_bosch_private.h" +#include "accelerometer_bosch_register.h" +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/core/types.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include +#include +#include +#include + +using std::forward_as_tuple; +using std::free; +using std::malloc; +using std::memcpy; +using std::min; +using std::piecewise_construct; +using std::stringstream; +using std::unordered_map; +using std::vector; + +#define CREATE_ACC_SIGNAL_SINGLE(offset) CREATE_ACC_SIGNAL(DataInterpreter::BOSCH_ACCELERATION_SINGLE_AXIS, 1, offset) +#define CREATE_ACC_SIGNAL(interpreter, channels, offset) new MblMwDataSignal(BOSCH_ACCEL_RESPONSE_HEADER, board, interpreter, \ + FirmwareConverter::BOSCH_ACCELERATION, channels, 2, 1, offset) +#define GET_CONFIG(x) ((x*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER)) + +const uint8_t MBL_MW_MODULE_ACC_TYPE_BMI160 = 1; ///< Constant identifying the BMI160 accelerometer module type +const uint8_t MBL_MW_MODULE_ACC_TYPE_BMA255 = 3; ///< Constant identifying the BMA255 accelerometer module type +const uint8_t MBL_MW_MODULE_ACC_TYPE_BMI270 = 4; ///< Constant identifying the BMI270 accelerometer module type + +const uint8_t BMI270_DEFAULT_CONFIG[]= { + 0xa8, 0x02, // acc range + 0x00, // feature enable + 0x00, // feature int enable + 0x88, 0x00, 0x00, // remap + 0x05, 0xE0, 0xAA, 0x38, 0x01, // any motion + 0x05, 0xE0, 0x90, 0x30, 0x02, // no motion + 0xFA, 0x00, 0x03, // sig motion + 0x2D, 0x01, 0xD4, 0x7B, 0x3B, 0x01, 0xDB, 0x7A, 0x04, 0x00, 0x3F, 0x7B, 0xCD, 0x6C, 0xC3, 0x4C, 0x04, // step counter 1 + 0x85, 0x09, 0xC3, 0x04, 0xEC, 0xE6, 0x0C, 0x46, 0x01, 0x00, 0x27, 0x00, 0x19, 0x00, 0x96, 0x00, 0x05, // step counter 2 + 0xA0, 0x00, 0x01, 0x00, 0x0C, 0x00, 0xF0, 0x3C, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x06, // step counter 3 + 0x00, 0x0E, 0x00, 0x00, 0x07, // step counter 4 + 0x05, 0x00, 0xEE, 0x06, 0x04, 0x00, 0xC8, 0x00, 0x08, // wrist wakeup + 0xA8, 0x05, 0xEE, 0x06, 0x00, 0x04, 0xBC, 0x02, 0xB3, 0x00, 0x85, 0x07, 0x09, // wristwakeup + 0x00, 0x00, 0x00, 0x00, // offset + 0x00 // fifo downs +}; +const uint8_t BMI160_DEFAULT_CONFIG[]= { + 0x28, 0x03, + 0x07, 0x30, 0x81, 0x0b, 0xc0, + 0x00, 0x14, 0x14, 0x14, + 0x04, 0x0a, + 0x18, 0x48, + 0x08, 0x11, + 0x00, 0x00 +}; +const uint8_t BMA255_DEFAULT_CONFIG[]= { + 0x0a, 0x03, + 0x09, 0x30, 0x81, 0x0f, 0xc0, + 0x00, 0x14, 0x14, + 0x04, 0x0a, + 0x18, 0x48, + 0x08, 0x11 +}; + +const float ORIENT_HYS_G_PER_STEP = 0.0625f; +const uint8_t FSR_BITMASKS[4]= {0x3, 0x5, 0x8, 0xc}, PACKED_ACC_REVISION= 1; +const uint8_t BMI270_FSR_BITMASKS[4]= {0x0, 0x1, 0x2, 0x3}; +const unordered_map BMA255_FSR_SCALE= {{0x3, 16384.f}, {0x5, 8192.f}, {0x8, 4096.f}, {0xc, 2048.f}}, + BMI160_FSR_SCALE= {{0x3, 16384.f}, {0x5, 8192.f}, {0x8, 4096.f}, {0xc, 2048.f}}, + BMI270_FSR_SCALE= {{0x0, 16384.f}, {0x1, 8192.f}, {0x2, 4096.f}, {0x3, 2048.f}}, + BOSCH_MOTION_THS_STEPS = {{0x3, 0.00391f}, {0x5, 0.00781f}, {0x8, 0.01563f}, {0xc, 0.03125f}}, + BOSCH_TAP_THS_STEPS = {{0x3, 0.0625f}, {0x5, 0.125f}, {0x8, 0.250f}, {0xc, 0.5f}}; +const ResponseHeader BOSCH_ACCEL_RESPONSE_HEADER(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::DATA_INTERRUPT)), + BOSCH_MOTION_DETECTOR(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::MOTION_INTERRUPT)), + BOSCH_ORIENTATION_DETECTOR(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::ORIENT_INTERRUPT)), + BOSCH_TAP_DETECTOR(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::TAP_INTERRUPT)), + BMI160_STEP_DETECTOR(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::STEP_DETECTOR_INTERRUPT)), + BMI160_STEP_COUNTER(MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerBmi160Register::STEP_COUNTER_DATA))), + BMI160_PACKED_ACCEL_RESPONSE_HEADER(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::PACKED_ACC_DATA)), + BMI270_MOTION_DETECTOR(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::MOTION_INTERRUPT)), + BMI270_STEP_DETECTOR(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::STEP_COUNT_INTERRUPT)), + BMI270_STEP_COUNTER(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::STEP_COUNT_INTERRUPT)), + BMI270_WRIST_DETECTOR(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::WRIST_INTERRUPT)), + BMI270_ACTIVITY_DETECTOR(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::ACTIVITY_INTERRUPT)), + BMI270_PACKED_ACCEL_RESPONSE_HEADER(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::PACKED_ACC_DATA)); + +struct AccBmi270Config { + struct { + uint8_t odr:4; //bit 0-4 + uint8_t bwp:3; + uint8_t us:1; // acc_conf.acc_filter_perf + uint8_t range:3; //bit 0-3 + uint8_t:5; + } acc; //ACC_RANGE, ACC_CONFIG 0x02, 0xa8 + struct { + uint8_t sig_motion:1; //bit 0 + uint8_t step_counter:1; + uint8_t activity_out:1; + uint8_t wrist_wakeup:1; + uint8_t wrist_gesture:1; + uint8_t no_motion:1; + uint8_t any_motion:1; + uint8_t step_detector:1; + } feature_enable; //FEATURE_ENABLE 0x00 + struct { + uint8_t sig_motion:1; //bit 0 + uint8_t step_counter:1; + uint8_t activity_out:1; + uint8_t wrist_wakeup:1; + uint8_t wrist_gesture:1; + uint8_t no_motion:1; + uint8_t any_motion:1; + uint8_t step_detector:1; + } feature_int_enable; //FEATURE_INTERRUPT_ENABLE 0x00 + struct { + struct { + struct { + uint8_t map_x_axis:2; //bit 0 + uint8_t map_x_axis_sign:1; + uint8_t map_y_axis:2; + uint8_t map_y_axis_sign:1; + uint8_t map_z_axis:2; + uint8_t map_z_axis_sign:1; + uint8_t:7; + } bitmap; + uint8_t index = 0; + } axis_remap; //REMAP 0x88 0x00 + struct { + struct { + uint8_t duration_0; //bit 0 + uint8_t duration_1:5; + uint8_t select_x:1; + uint8_t select_y:1; + uint8_t select_z:1; + uint8_t threshold_0; //bit 0 + uint8_t threshold_1:3; + uint8_t :5; + } bitmap; + uint8_t index = 1; + } any_motion; //ANYMOTION 0x05 0xE0 + struct { + struct { + uint8_t duration_0; //bit 0 + uint8_t duration_1:5; + uint8_t select_x:1; + uint8_t select_y:1; + uint8_t select_z:1; + uint8_t threshold_0; + uint8_t threshold_1:3; + uint8_t :5; + } bitmap; + uint8_t index = 2; + } no_motion; //NOMOTION 0x05 0xE0 + struct { + struct { + uint8_t block_size0; //bit 0 + uint8_t block_size1; + } bitmap; + uint8_t index = 3; + } sig_motion; //SIGMOTION + struct { + struct { + uint8_t param_10; + uint8_t param_11; + uint8_t param_20; + uint8_t param_21; + uint8_t param_30; + uint8_t param_31; + uint8_t param_40; + uint8_t param_41; + uint8_t param_50; + uint8_t param_51; + uint8_t param_60; + uint8_t param_61; + uint8_t param_70; + uint8_t param_71; + uint8_t param_80; + uint8_t param_81; + } bitmap; + uint8_t index = 4; + } step_counter_0; //STEPCOUNTER1 + struct { + struct { + uint8_t param_90; + uint8_t param_91; + uint8_t param_100; + uint8_t param_101; + uint8_t param_110; + uint8_t param_111; + uint8_t param_120; + uint8_t param_121; + uint8_t param_130; + uint8_t param_131; + uint8_t param_140; + uint8_t param_141; + uint8_t param_150; + uint8_t param_151; + uint8_t param_160; + uint8_t param_161; + } bitmap; + uint8_t index = 5; + } step_counter_1; //STEPCOUNTER2 0x85 0x09 + struct { + struct { + uint8_t param_170; + uint8_t param_171; + uint8_t param_180; + uint8_t param_181; + uint8_t param_190; + uint8_t param_191; + uint8_t param_200; + uint8_t param_201; + uint8_t param_210; + uint8_t param_211; + uint8_t param_220; + uint8_t param_221; + uint8_t param_230; + uint8_t param_231; + uint8_t param_240; + uint8_t param_241; + } bitmap; + uint8_t index = 6; + } step_counter_2; //STEPCOUNTER3 0xA0 0x00 + struct { + struct { + uint8_t param_250; //bit 0-7 + uint8_t param_251; //bit 8-15 + uint8_t watermark_level_0; //bit 0-7 + uint8_t watermark_level_1:2;//bit 0-1 + uint8_t reset_counter:1; //bit 2 + uint8_t:5; //bit 3-7 + } bitmap; + uint8_t index = 7; + } step_counter_3; //STEPCOUNTER4 0x0E 0x00 + struct { + struct { + uint8_t:4; //out_conf //bit 0 + uint8_t wearable_arm:1; //bit 4 + uint8_t:3; //enable + uint8_t:8; + uint8_t min_flick_peak0; + uint8_t min_flick_peak1; + uint8_t min_flick_samples0; + uint8_t min_flick_samples1; + uint8_t max_duration0; + uint8_t max_duration1; + } bitmap; + uint8_t index = 8; + } wrist_gesture; //WRISTGESTURE 0x05 0x00 + struct { + struct { + uint8_t min_angle_focus0; + uint8_t min_angle_focus1; + uint8_t min_angle_non_focus0; + uint8_t min_angle_non_focus1; + uint8_t max_tilt_lr0; + uint8_t max_tilt_lr1; + uint8_t max_tilt_ll0; + uint8_t max_tilt_ll1; + uint8_t max_tilt_pd0; + uint8_t max_tilt_pd1; + uint8_t max_tilt_pu0; + uint8_t max_tilt_pu1; + } bitmap; + uint8_t index = 9; + } wrist_wakeup; //WRISTWAKEUP 0xA8 0x05 0xEE 0x06 0x00 0x04 0xBC 0x02 0xB3 0x00 0x85 0x07 + } feature_config; //FEATURE_CONFIG + struct { + uint8_t spi_en:1; //bit 0 + uint8_t i2c_wdt_sel:1; + uint8_t i2c_wdt_en:1; + uint8_t acc_off_en:1; + uint8_t:4; + uint8_t off_acc_x:8; + uint8_t off_acc_y:8; + uint8_t off_acc_z:8; + } nv_offset; //OFFSET 0x00, 0x00, 0x00, 0x00 + struct { + uint8_t gyr_fifo_downs:3; //bit 0 + uint8_t gyr_fifo_filt_data:1; + uint8_t acc_fifo_downs:3; + uint8_t acc_fifo_filt_data:1; + } fifo_downs; //FIFO_DOWNS + + inline void set_output_data_rate(MblMwAccBmi270Odr odr) { + acc.odr= odr + 1; + } + inline void set_range(MblMwAccBoschRange range) { + acc.range= BMI270_FSR_BITMASKS[range]; + } +}; + +struct AccBmi160Config { + struct { + uint8_t odr:4; //bit 0-3 ACC_CONF + uint8_t bwp:3; //bit 4-6 + uint8_t us:1; //bit 7 + uint8_t range:4; //bit 0-3 ACC_RANGE + uint8_t:4; //bit 4-7 + } acc; //DATA_CONFIG + struct { + uint8_t low_dur; + uint8_t low_th; + uint8_t low_hys:2; + uint8_t low_mode:1; + uint8_t :3; + uint8_t high_hys:2; + uint8_t high_dur; + uint8_t high_th; + } lowhigh; + struct { + uint8_t anym_dur:2; + uint8_t slo_no_mot_dur:6; + uint8_t anym_th; + uint8_t slo_no_mot_th; + uint8_t int_no_mot_sel:2; + uint8_t sig_mot_skip:2; + uint8_t sig_mot_proof:2; + uint8_t :2; + } motion; + struct { + uint8_t dur:3; + uint8_t :3; + uint8_t shock:1; + uint8_t quiet:1; + uint8_t th:5; + uint8_t :3; + } tap; + struct { + uint8_t mode:2; + uint8_t blocking:2; + uint8_t hyst:4; + uint8_t theta:6; + uint8_t ud_en:1; + uint8_t axes_ex:1; + } orientation; + struct { + uint8_t theta:6; + uint8_t :2; + uint8_t hy:3; + uint8_t :1; + uint8_t hold_time:2; + uint8_t :2; + } flat; + struct { + uint8_t steptime_min:3; + uint8_t min_threshold:2; + uint8_t alpha:3; + uint8_t min_step_buf:3; + uint8_t step_cnt_en:1; + uint8_t :4; + } step_counter; + + inline void set_output_data_rate(MblMwAccBmi160Odr odr) { + acc.odr= odr + 1; + } + inline void set_range(MblMwAccBoschRange range) { + acc.range= FSR_BITMASKS[range]; + } +}; + +struct AccBma255Config { + struct { + uint8_t bw:5; + uint8_t :3; + uint8_t range:4; + uint8_t :4; + } acc; + struct { + uint8_t low_dur; + uint8_t low_th; + uint8_t low_hy:2; + uint8_t low_mode:1; + uint8_t :3; + uint8_t high_hy:2; + uint8_t high_dur; + uint8_t high_th; + } lowhigh; + struct { + uint8_t slope_dur:2; + uint8_t slo_no_mot_dur:6; + uint8_t slope_th; + uint8_t slow_no_mot_th; + } motion; + struct { + uint8_t dur:3; + uint8_t :3; + uint8_t shock:1; + uint8_t quiet:1; + uint8_t th:5; + uint8_t :1; + uint8_t samp:2; + } tap; + struct { + uint8_t mode:2; + uint8_t blocking:2; + uint8_t hyst:3; + uint8_t :1; + uint8_t theta:6; + uint8_t ud_en:1; + uint8_t :1; + } orientation; + struct { + uint8_t theta:6; + uint8_t :2; + uint8_t hy:3; + uint8_t :1; + uint8_t hold_time:2; + uint8_t :2; + } flat; + + inline void set_output_data_rate(MblMwAccBma255Odr odr) { + acc.bw= odr + 8; + } + inline void set_range(MblMwAccBoschRange range) { + acc.range= FSR_BITMASKS[range]; + } +}; + +struct AccBoschState { + MblMwFnBoardPtrInt read_config_completed; + void *read_config_context; + uint8_t motion_mask; + MblMwFnBoardPtrInt read_step_counter_handler; + void *read_step_counter_context; +}; + +static unordered_map states; + +static int32_t received_config_response(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + auto config= &((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc; + memcpy(config, response + 2, sizeof(*config)); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + auto config= &((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc; + memcpy(config, response + 2, sizeof(*config)); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto config= &((AccBmi270Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc; + memcpy(config, response + 2, sizeof(*config)); + break; + } + default: + return MBL_MW_STATUS_OK; + } + + auto callback = states[board].read_config_completed; + auto context = states[board].read_config_context; + states[board].read_config_completed = nullptr; + states[board].read_config_context = nullptr; + callback(context, board, MBL_MW_STATUS_OK); + + return MBL_MW_STATUS_OK; +} + +#include + +static int32_t received_step_counter_response(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + uint32_t step_count = 0; + if (len == 0x04) { + uint16_t first = response[len-2]; + uint16_t second = response[len-1] << 8; + uint16_t tempy = second | first; + step_count = tempy; + } + + auto step_callback = states[board].read_step_counter_handler; + auto step_context = states[board].read_step_counter_context; + states[board].read_step_counter_handler = nullptr; + states[board].read_step_counter_context = nullptr; + step_callback(step_context, board, step_count); + + return MBL_MW_STATUS_OK; +} + +static void init_accelerometer_bosch(MblMwMetaWearBoard *board, void *config) { + if (!board->module_config.count(MBL_MW_MODULE_ACCELEROMETER)) { + board->module_config[MBL_MW_MODULE_ACCELEROMETER] = config; + } else { + free(config); + } + + MblMwDataSignal* acc; + if (board->module_events.count(BOSCH_ACCEL_RESPONSE_HEADER)) { + acc = dynamic_cast(board->module_events[BOSCH_ACCEL_RESPONSE_HEADER]); + } else { + acc = CREATE_ACC_SIGNAL(DataInterpreter::BOSCH_ACCELERATION, 3, 0); + board->module_events[BOSCH_ACCEL_RESPONSE_HEADER] = acc; + } + if (!acc->components.size()) { + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(0)); + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(2)); + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(4)); + } + board->responses[BOSCH_ACCEL_RESPONSE_HEADER]= response_handler_data_no_id; + + if (!board->module_events.count(BOSCH_MOTION_DETECTOR)) { + board->module_events[BOSCH_MOTION_DETECTOR]= new MblMwDataSignal(BOSCH_MOTION_DETECTOR, board, + DataInterpreter::BOSCH_ANY_MOTION, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + if (!board->module_events.count(BOSCH_ORIENTATION_DETECTOR)) { + board->module_events[BOSCH_ORIENTATION_DETECTOR]= new MblMwDataSignal(BOSCH_ORIENTATION_DETECTOR, board, + DataInterpreter::SENSOR_ORIENTATION, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + if (!board->module_events.count(BOSCH_TAP_DETECTOR)) { + board->module_events[BOSCH_TAP_DETECTOR]= new MblMwDataSignal(BOSCH_TAP_DETECTOR, board, + DataInterpreter::BOSCH_TAP, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + + if (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).revision >= PACKED_ACC_REVISION) { + if (!board->module_events.count(BMI160_PACKED_ACCEL_RESPONSE_HEADER)) { + board->module_events[BMI160_PACKED_ACCEL_RESPONSE_HEADER]= new MblMwDataSignal(BMI160_PACKED_ACCEL_RESPONSE_HEADER, board, + DataInterpreter::BOSCH_ACCELERATION, FirmwareConverter::BOSCH_ACCELERATION, 3, 2, 1, 0); + } + board->responses[BMI160_PACKED_ACCEL_RESPONSE_HEADER]= response_handler_packed_data; + } + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerBmi160Register::DATA_CONFIG))), + forward_as_tuple(received_config_response)); + board->responses.emplace(BOSCH_MOTION_DETECTOR, response_handler_data_no_id); + board->responses.emplace(BOSCH_TAP_DETECTOR, response_handler_data_no_id); + board->responses.emplace(BOSCH_ORIENTATION_DETECTOR, response_handler_data_no_id); + + AccBoschState newState = {nullptr, nullptr, 0x0, nullptr, nullptr}; + states.insert({board, newState}); +} + +void init_accelerometer_bmi270(MblMwMetaWearBoard *board) { + AccBmi270Config* config = (AccBmi270Config*) malloc(sizeof(AccBmi270Config)); + memcpy(config, BMI270_DEFAULT_CONFIG, sizeof(BMI270_DEFAULT_CONFIG)); + + if (!board->module_config.count(MBL_MW_MODULE_ACCELEROMETER)) { + board->module_config[MBL_MW_MODULE_ACCELEROMETER] = config; + } else { + free(config); + } + + MblMwDataSignal* acc; + if (board->module_events.count(BOSCH_ACCEL_RESPONSE_HEADER)) { + acc = dynamic_cast(board->module_events[BOSCH_ACCEL_RESPONSE_HEADER]); + } else { + acc = CREATE_ACC_SIGNAL(DataInterpreter::BOSCH_ACCELERATION, 3, 0); + board->module_events[BOSCH_ACCEL_RESPONSE_HEADER] = acc; + } + if (!acc->components.size()) { + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(0)); + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(2)); + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(4)); + } + board->responses[BOSCH_ACCEL_RESPONSE_HEADER]= response_handler_data_no_id; + + if (!board->module_events.count(BMI270_MOTION_DETECTOR)) { + board->module_events[BMI270_MOTION_DETECTOR]= new MblMwDataSignal(BMI270_MOTION_DETECTOR, board, + DataInterpreter::UINT32, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + board->responses.emplace(BMI270_MOTION_DETECTOR, response_handler_data_no_id); + + if (!board->module_events.count(BMI270_STEP_DETECTOR)) { + board->module_events[BMI270_STEP_DETECTOR] = new MblMwDataSignal(BMI270_STEP_DETECTOR, board, + DataInterpreter::UINT32, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + board->responses[BMI270_STEP_DETECTOR]= response_handler_data_no_id; + + if (!board->module_events.count(BMI270_STEP_COUNTER)) { + board->module_events[BMI270_STEP_COUNTER] = new MblMwDataSignal(BMI270_STEP_COUNTER, board, + DataInterpreter::UINT32, FirmwareConverter::DEFAULT, 1, 2, 0, 0); + } + board->responses[BMI270_STEP_COUNTER]= response_handler_data_no_id; + + if (!board->module_events.count(BMI270_WRIST_DETECTOR)) { + board->module_events[BMI270_WRIST_DETECTOR] = new MblMwDataSignal(BMI270_WRIST_DETECTOR, board, + DataInterpreter::BMI270_GESTURE, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + board->responses[BMI270_WRIST_DETECTOR]= response_handler_data_no_id; + + if (!board->module_events.count(BMI270_ACTIVITY_DETECTOR)) { + board->module_events[BMI270_ACTIVITY_DETECTOR] = new MblMwDataSignal(BMI270_ACTIVITY_DETECTOR, board, + DataInterpreter::BMI270_ACTIVITY, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + board->responses[BMI270_ACTIVITY_DETECTOR]= response_handler_data_no_id; + + if (!board->module_events.count(BMI270_PACKED_ACCEL_RESPONSE_HEADER)) { + board->module_events[BMI270_PACKED_ACCEL_RESPONSE_HEADER]= new MblMwDataSignal(BMI270_PACKED_ACCEL_RESPONSE_HEADER, board, + DataInterpreter::BOSCH_ACCELERATION, FirmwareConverter::BOSCH_ACCELERATION, 3, 2, 1, 0); + } + board->responses[BMI270_PACKED_ACCEL_RESPONSE_HEADER]= response_handler_packed_data; + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerBmi270Register::DATA_CONFIG))), + forward_as_tuple(received_config_response)); + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerBmi270Register::STEP_COUNT_INTERRUPT))), + forward_as_tuple(received_step_counter_response)); + + AccBoschState newState = {nullptr, nullptr, 0x0, nullptr, nullptr}; + states.insert({board, newState}); +} + +void init_accelerometer_bmi160(MblMwMetaWearBoard *board) { + AccBmi160Config* new_config = (AccBmi160Config*) malloc(sizeof(AccBmi160Config)); + memcpy(new_config, BMI160_DEFAULT_CONFIG, sizeof(BMI160_DEFAULT_CONFIG)); + + if (!board->module_events.count(BMI160_STEP_DETECTOR)) { + board->module_events[BMI160_STEP_DETECTOR] = new MblMwDataSignal(BMI160_STEP_DETECTOR, board, + DataInterpreter::UINT32, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + board->responses[BMI160_STEP_DETECTOR]= response_handler_data_no_id; + + if (!board->module_events.count(BMI160_STEP_COUNTER)) { + board->module_events[BMI160_STEP_COUNTER] = new MblMwDataSignal(BMI160_STEP_COUNTER, board, + DataInterpreter::UINT32, FirmwareConverter::DEFAULT, 1, 2, 0, 0); + } + board->responses[BMI160_STEP_COUNTER]= response_handler_data_no_id; + + init_accelerometer_bosch(board, new_config); +} + +void init_accelerometer_bma255(MblMwMetaWearBoard *board) { + AccBma255Config* new_config = (AccBma255Config*) malloc(sizeof(AccBma255Config)); + memcpy(new_config, BMA255_DEFAULT_CONFIG, sizeof(BMA255_DEFAULT_CONFIG)); + + init_accelerometer_bosch(board, new_config); +} + +void free_accelerometer_bosch(MblMwMetaWearBoard *board) { + states.erase(board); +} + +void serialize_accelerometer_bmi270_config(const MblMwMetaWearBoard* board, vector& state) { + SERIALIZE_MODULE_CONFIG(AccBmi270Config, MBL_MW_MODULE_ACCELEROMETER); +} + +void serialize_accelerometer_bmi160_config(const MblMwMetaWearBoard* board, vector& state) { + SERIALIZE_MODULE_CONFIG(AccBmi160Config, MBL_MW_MODULE_ACCELEROMETER); +} + +void serialize_accelerometer_bma255_config(const MblMwMetaWearBoard* board, vector& state) { + SERIALIZE_MODULE_CONFIG(AccBma255Config, MBL_MW_MODULE_ACCELEROMETER); +} + +void deserialize_accelerometer_bmi270_config(MblMwMetaWearBoard* board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(AccBmi270Config, MBL_MW_MODULE_ACCELEROMETER); +} + +void deserialize_accelerometer_bmi160_config(MblMwMetaWearBoard* board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(AccBmi160Config, MBL_MW_MODULE_ACCELEROMETER); +} + +void deserialize_accelerometer_bma255_config(MblMwMetaWearBoard* board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(AccBma255Config, MBL_MW_MODULE_ACCELEROMETER); +} + +void read_accelerometer_bosch_acceleration_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed) { + states[board].read_config_context = context; + states[board].read_config_completed = completed; + + uint8_t command[2]= {MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerBmi160Register::DATA_CONFIG))}; + SEND_COMMAND; +} + +float bosch_get_data_scale(const MblMwMetaWearBoard *board) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: + return BMI160_FSR_SCALE.at(((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc.range); + case MBL_MW_MODULE_ACC_TYPE_BMA255: + return BMA255_FSR_SCALE.at(((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc.range); + case MBL_MW_MODULE_ACC_TYPE_BMI270: + return BMI270_FSR_SCALE.at(((AccBmi270Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc.range); + default: + return 1.f; + } +} + +MblMwDataSignal* mbl_mw_acc_bosch_get_acceleration_data_signal(const MblMwMetaWearBoard *board) { + auto implementation= board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation; + if (implementation != MBL_MW_MODULE_ACC_TYPE_BMI160 && implementation != MBL_MW_MODULE_ACC_TYPE_BMA255 && implementation != MBL_MW_MODULE_ACC_TYPE_BMI270) { + return nullptr; + } + GET_DATA_SIGNAL(BOSCH_ACCEL_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_acc_bosch_get_high_freq_acceleration_data_signal(const MblMwMetaWearBoard* board) { + return mbl_mw_acc_bosch_get_packed_acceleration_data_signal(board); +} + +MblMwDataSignal* mbl_mw_acc_bosch_get_packed_acceleration_data_signal(const MblMwMetaWearBoard* board) { + auto implementation= board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation; + if (implementation == MBL_MW_MODULE_ACC_TYPE_BMI160) { + GET_DATA_SIGNAL(BMI160_PACKED_ACCEL_RESPONSE_HEADER); + } else if (implementation == MBL_MW_MODULE_ACC_TYPE_BMA255) { + GET_DATA_SIGNAL(BMI160_PACKED_ACCEL_RESPONSE_HEADER); + } else if (implementation == MBL_MW_MODULE_ACC_TYPE_BMI270) { + GET_DATA_SIGNAL(BMI270_PACKED_ACCEL_RESPONSE_HEADER); + } else { + return nullptr; + } + +} + +MblMwDataSignal* mbl_mw_acc_bmi160_get_step_counter_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(BMI160_STEP_COUNTER); +} + +MblMwDataSignal* mbl_mw_acc_bmi160_get_step_detector_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(BMI160_STEP_DETECTOR); +} + +MblMwDataSignal* mbl_mw_acc_bmi270_get_step_counter_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(BMI270_STEP_COUNTER); +} + +MblMwDataSignal* mbl_mw_acc_bmi270_get_step_detector_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(BMI270_STEP_DETECTOR); +} + +MblMwDataSignal* mbl_mw_acc_bmi270_get_wrist_detector_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(BMI270_WRIST_DETECTOR); +} + +MblMwDataSignal* mbl_mw_acc_bmi270_get_activity_detector_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(BMI270_ACTIVITY_DETECTOR); +} + +MblMwDataSignal* mbl_mw_acc_bosch_get_orientation_detection_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(BOSCH_ORIENTATION_DETECTOR); +} + +MblMwDataSignal* mbl_mw_acc_bosch_get_motion_data_signal(const MblMwMetaWearBoard* board) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: + GET_DATA_SIGNAL(BMI270_MOTION_DETECTOR); + break; + default: + GET_DATA_SIGNAL(BOSCH_MOTION_DETECTOR); + } +} + +MblMwDataSignal* mbl_mw_acc_bosch_get_tap_data_signal(const MblMwMetaWearBoard* board) { + GET_DATA_SIGNAL(BOSCH_TAP_DETECTOR); +} + +void mbl_mw_acc_bmi270_set_odr(MblMwMetaWearBoard *board, MblMwAccBmi270Odr odr) { + auto config= (AccBmi270Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER); + + config->set_output_data_rate(odr); + config->acc.us= 1; + config->acc.bwp= 2; + if (odr < MBL_MW_ACC_BMI270_ODR_12_5Hz) { + config->acc.us= 0; + } +} + +void mbl_mw_acc_bmi160_set_odr(MblMwMetaWearBoard *board, MblMwAccBmi160Odr odr) { + auto config= (AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER); + + config->set_output_data_rate(odr); + if (odr < MBL_MW_ACC_BMI160_ODR_12_5Hz) { + config->acc.us= 1; + config->acc.bwp= 0; + } else { + config->acc.us= 0; + config->acc.bwp= 2; + } +} + +void mbl_mw_acc_bma255_set_odr(MblMwMetaWearBoard *board, MblMwAccBma255Odr odr) { + ((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->set_output_data_rate(odr); +} + +void mbl_mw_acc_bosch_set_range(MblMwMetaWearBoard *board, MblMwAccBoschRange range) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: + ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->set_range(range); + break; + case MBL_MW_MODULE_ACC_TYPE_BMA255: + ((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->set_range(range); + break; + case MBL_MW_MODULE_ACC_TYPE_BMI270: + ((AccBmi270Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->set_range(range); + break; + } +} + +void mbl_mw_acc_bosch_write_acceleration_config(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::DATA_CONFIG)}; + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + auto config= ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc; + memcpy(command + 2, &config, sizeof(config)); + SEND_COMMAND; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + auto config= ((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc; + memcpy(command + 2, &config, sizeof(config)); + SEND_COMMAND; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto config= ((AccBmi270Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc; + memcpy(command + 2, &config, sizeof(config)); + SEND_COMMAND; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bmi160_set_step_counter_mode(MblMwMetaWearBoard* board, MblMwAccBmi160StepCounterMode mode) { + auto config= (uint16_t*) &((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->step_counter; + + switch (mode) { + case MBL_MW_ACC_BMI160_STEP_COUNTER_MODE_NORMAL: + *config= 0x0315; + break; + case MBL_MW_ACC_BMI160_STEP_COUNTER_MODE_SENSITIVE: + *config= 0x002d; + break; + case MBL_MW_ACC_BMI160_STEP_COUNTER_MODE_ROBUST: + *config= 0x071d; + break; + } +} + +void mbl_mw_acc_bmi160_enable_step_counter(MblMwMetaWearBoard* board) { + ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->step_counter.step_cnt_en= 1; +} + +void mbl_mw_acc_bmi160_disable_step_counter(MblMwMetaWearBoard* board) { + ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->step_counter.step_cnt_en= 0; +} + +void mbl_mw_acc_bmi160_write_step_counter_config(const MblMwMetaWearBoard* board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::STEP_DETECTOR_CONFIG)}; + auto config= ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->step_counter; + + memcpy(command + 2, &config, sizeof(config)); + SEND_COMMAND; +} + +void mbl_mw_acc_bmi160_reset_step_counter(const MblMwMetaWearBoard* board) { + uint8_t command[2]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::STEP_COUNTER_RESET)}; + SEND_COMMAND; +} + +void mbl_mw_acc_bmi160_enable_step_detector(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::STEP_DETECTOR_INTERRUPT_EN), 1, 0}; + SEND_COMMAND; +} + +void mbl_mw_acc_bmi160_disable_step_detector(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::STEP_DETECTOR_INTERRUPT_EN), 0, 1}; + SEND_COMMAND; +} + +void mbl_mw_acc_bmi270_set_step_counter_trigger(MblMwMetaWearBoard* board, uint16_t trigger) { + if (trigger >= 1 && trigger <= 1023) { + auto lower_8 = trigger & 0x00ff; + auto higher_2 = (trigger & 0x0300) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.bitmap.watermark_level_0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.bitmap.watermark_level_1 = higher_2; + } else { + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.bitmap.watermark_level_0 = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.bitmap.watermark_level_1 = 0; + } +} + +void mbl_mw_acc_bmi270_enable_step_counter(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x02, 0x00}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x02, 0x00}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_disable_step_counter(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x00, 0x02}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x00, 0x02}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_write_step_counter_config(const MblMwMetaWearBoard* board) { + uint8_t command[7]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_CONFIG), ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.index}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.bitmap; + memcpy(command + 3, &config, sizeof(config)); + SEND_COMMAND; +} + +void mbl_mw_acc_bmi270_reset_step_counter(const MblMwMetaWearBoard* board) { + uint8_t command[7]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_CONFIG), ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.index}; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.bitmap.reset_counter=1; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.bitmap; + memcpy(command + 3, &config, sizeof(config)); + SEND_COMMAND; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.step_counter_3.bitmap.reset_counter=0; +} + +void mbl_mw_acc_bmi270_read_step_counter(MblMwMetaWearBoard* board, void* context, MblMwFnBoardPtrInt handler) { + states[board].read_step_counter_handler = handler; + states[board].read_step_counter_context = context; + + uint8_t command[2]= {MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerBmi270Register::STEP_COUNT_INTERRUPT))}; + SEND_COMMAND; +} + +void mbl_mw_acc_bmi270_enable_step_detector(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x80, 0x00}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x80, 0x00}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_disable_step_detector(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x00, 0x80}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x00, 0x80}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bosch_set_orientation_hysteresis(MblMwMetaWearBoard *board, float hysteresis) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->orientation.hyst = + min((uint8_t) 0xf, (uint8_t) (hysteresis / ORIENT_HYS_G_PER_STEP)); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + ((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->orientation.hyst = + min((uint8_t) 0x7, (uint8_t) (hysteresis / ORIENT_HYS_G_PER_STEP)); + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_orientation_mode(MblMwMetaWearBoard *board, MblMwAccBoschOrientationMode mode) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->orientation.mode = (uint8_t) mode; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + ((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->orientation.mode = (uint8_t) mode; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_write_orientation_config(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::ORIENT_CONFIG)}; + + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + auto config= ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->orientation; + memcpy(command + 2, &config, sizeof(config)); + SEND_COMMAND; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + auto config= ((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->orientation; + memcpy(command + 2, &config, sizeof(config)); + SEND_COMMAND; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_quiet_time(MblMwMetaWearBoard *board, MblMwAccBoschTapQuietTime time) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + GET_CONFIG(AccBmi160Config)->tap.quiet = time; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + GET_CONFIG(AccBma255Config)->tap.quiet = time; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_shock_time(MblMwMetaWearBoard *board, MblMwAccBoschTapShockTime time) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + GET_CONFIG(AccBmi160Config)->tap.shock = time; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + GET_CONFIG(AccBma255Config)->tap.shock = time; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_double_tap_window(MblMwMetaWearBoard *board, MblMwAccBoschDoubleTapWindow window) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + GET_CONFIG(AccBmi160Config)->tap.dur = window; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + GET_CONFIG(AccBma255Config)->tap.dur = window; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_threshold(MblMwMetaWearBoard *board, float threshold) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + auto config = GET_CONFIG(AccBmi160Config); + config->tap.th = threshold / BOSCH_TAP_THS_STEPS.at(config->acc.range); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + auto config = GET_CONFIG(AccBma255Config); + config->tap.th = threshold / BOSCH_TAP_THS_STEPS.at(config->acc.range); + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_write_tap_config(const MblMwMetaWearBoard *board) { + vector command = {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::TAP_CONFIG)}; + + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + auto config= GET_CONFIG(AccBmi160Config)->tap; + command.insert(command.end(), (uint8_t*) &config, (uint8_t*) (&config + 1)); + send_command(board, command.data(), (uint8_t) command.size()); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + auto config= GET_CONFIG(AccBma255Config)->tap; + command.insert(command.end(), (uint8_t*) &config, (uint8_t*) (&config + 1)); + send_command(board, command.data(), (uint8_t) command.size()); + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_enable_tap_detection(const MblMwMetaWearBoard *board, uint8_t enable_single, uint8_t enable_double) { + uint8_t mask = 0; + if (enable_single) { + mask|= 0x2; + } + if (enable_double) { + mask|= 0x1; + } + + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::TAP_INTERRUPT_ENABLE), mask, 0}; + SEND_COMMAND; +} + +void mbl_mw_acc_bosch_disable_tap_detection(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::TAP_INTERRUPT_ENABLE), 0x00, 0x03}; + SEND_COMMAND; +} + +void mbl_mw_acc_bosch_set_any_motion_count(MblMwMetaWearBoard *board, uint8_t count) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->motion.anym_dur = (count - 1); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + ((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->motion.slope_dur = (count - 1); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.any_motion.bitmap.duration_0 = count; + // HARDCODED TO 0 + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.any_motion.bitmap.duration_1 = 0; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_any_motion_threshold(MblMwMetaWearBoard *board, float threshold) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + auto config = (AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER); + config->motion.anym_th = threshold / BOSCH_MOTION_THS_STEPS.at(config->acc.range); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + auto config = (AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER); + config->motion.slope_th = threshold / BOSCH_MOTION_THS_STEPS.at(config->acc.range); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = (uint16_t)threshold & 0x00ff; + auto higher_3 = ((uint16_t)threshold & 0x0700) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.any_motion.bitmap.threshold_0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.any_motion.bitmap.threshold_1 = higher_3; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_sig_motion_blocksize(MblMwMetaWearBoard *board, uint16_t blocksize) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = blocksize & 0x00ff; + auto higher_8 = (blocksize & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.sig_motion.bitmap.block_size0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.sig_motion.bitmap.block_size1 = higher_8; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_no_motion_count(MblMwMetaWearBoard *board, uint8_t count) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.no_motion.bitmap.duration_0 = count; + // HARDCODED TO 0 + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.no_motion.bitmap.duration_1 = 0; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_set_no_motion_threshold(MblMwMetaWearBoard *board, float threshold) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = (uint16_t)threshold & 0x00ff; + auto higher_3 = ((uint16_t)threshold & 0x0700) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.no_motion.bitmap.threshold_0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.no_motion.bitmap.threshold_1 = higher_3; + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_write_motion_config(const MblMwMetaWearBoard *board, MblMwAccBoschMotion type) { + vector command = {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::MOTION_CONFIG)}; + states.at(board).motion_mask = 0x7; + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: { + auto config= ((AccBmi160Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->motion; + command.insert(command.end(), (uint8_t*) &config, (uint8_t*) (&config + 1)); + send_command(board, command.data(), (uint8_t) command.size()); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + auto config= ((AccBma255Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->motion; + command.insert(command.end(), (uint8_t*) &config, (uint8_t*) (&config + 1)); + send_command(board, command.data(), (uint8_t) command.size()); + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + switch(type) { + case MBL_MW_ACC_BOSCH_MOTION_SIGMOTION: { + uint8_t command[5]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_CONFIG), ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.sig_motion.index}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.sig_motion.bitmap; + memcpy(command + 3, &config, sizeof(config)); + SEND_COMMAND; + break; + } + case MBL_MW_ACC_BOSCH_MOTION_NOMOTION: { + uint8_t command[7]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_CONFIG), ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.no_motion.index}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.no_motion.bitmap; + memcpy(command + 3, &config, sizeof(config)); + SEND_COMMAND; + break; + } + case MBL_MW_ACC_BOSCH_MOTION_ANYMOTION: { + uint8_t command[7]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_CONFIG), ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.any_motion.index}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.any_motion.bitmap; + memcpy(command + 3, &config, sizeof(config)); + SEND_COMMAND; + break; + } + } + break; + } + default: + return; + } +} + +void mbl_mw_acc_bosch_enable_motion_detection(const MblMwMetaWearBoard *board, MblMwAccBoschMotion type) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::MOTION_INTERRUPT_ENABLE), states.at(board).motion_mask, 0}; + SEND_COMMAND; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + switch(type) { + case MBL_MW_ACC_BOSCH_MOTION_SIGMOTION: { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x01, 0x00}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x01, 0x00}; + send_command(board, command2, sizeof(command2)); + break; + } + case MBL_MW_ACC_BOSCH_MOTION_NOMOTION: { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x20, 0x00}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x20, 0x00}; + send_command(board, command2, sizeof(command2)); + break; + } + case MBL_MW_ACC_BOSCH_MOTION_ANYMOTION: { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x40, 0x00}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x40, 0x00}; + send_command(board, command2, sizeof(command2)); + break; + } + } + break; + } + } +} + +void mbl_mw_acc_bosch_disable_motion_detection(const MblMwMetaWearBoard *board, MblMwAccBoschMotion type) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI160: + case MBL_MW_MODULE_ACC_TYPE_BMA255: { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::MOTION_INTERRUPT_ENABLE), 0, 0x7f}; + SEND_COMMAND; + break; + } + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + switch(type) { + case MBL_MW_ACC_BOSCH_MOTION_SIGMOTION: { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x00, 0x01}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x00, 0x01}; + send_command(board, command2, sizeof(command2)); + break; + } + case MBL_MW_ACC_BOSCH_MOTION_NOMOTION: { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x00, 0x20}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x00, 0x20}; + send_command(board, command2, sizeof(command2)); + break; + } + case MBL_MW_ACC_BOSCH_MOTION_ANYMOTION: { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x00, 0x40}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x00, 0x40}; + send_command(board, command2, sizeof(command2)); + break; + } + } + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_gesture_armside(const MblMwMetaWearBoard *board, uint8_t side) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + if (side == 1) { + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap.wearable_arm = 1; + } else if (side == 0) { + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap.wearable_arm = 0; + } + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_gesture_peak(const MblMwMetaWearBoard *board, uint16_t peak) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = peak & 0x00ff; + auto higher_8 = (peak & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap.min_flick_peak0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap.min_flick_peak1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_gesture_samples(const MblMwMetaWearBoard *board, uint16_t samples) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = samples & 0x00ff; + auto higher_8 = (samples & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap.min_flick_samples0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap.min_flick_samples1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_gesture_duration(const MblMwMetaWearBoard *board, uint16_t side) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = side & 0x00ff; + auto higher_8 = (side & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap.max_duration0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap.max_duration1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_write_wrist_gesture_config(const MblMwMetaWearBoard* board) { + uint8_t command[11]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_CONFIG), ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.index}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_gesture.bitmap; + memcpy(command + 3, &config, sizeof(config)); + SEND_COMMAND; +} + +void mbl_mw_acc_bmi270_enable_wrist_gesture(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x10, 0x00}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x10, 0x00}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_disable_wrist_gesture(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x00, 0x10}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x00, 0x10}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_wrist_wakeup_angle_focus(const MblMwMetaWearBoard *board, uint16_t angle) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = angle & 0x00ff; + auto higher_8 = (angle & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.min_angle_focus0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.min_angle_focus1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_wakeup_angle_nonfocus(const MblMwMetaWearBoard *board, uint16_t angle) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = angle & 0x00ff; + auto higher_8 = (angle & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.min_angle_non_focus0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.min_angle_non_focus1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_wakeup_tilt_lr(const MblMwMetaWearBoard *board, uint16_t angle) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = angle & 0x00ff; + auto higher_8 = (angle & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.max_tilt_lr0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.max_tilt_lr1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_wakeup_tilt_ll(const MblMwMetaWearBoard *board, uint16_t angle) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = angle & 0x00ff; + auto higher_8 = (angle & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.max_tilt_ll0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.max_tilt_ll1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_wakeup_tilt_pd(const MblMwMetaWearBoard *board, uint16_t angle) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = angle & 0x00ff; + auto higher_8 = (angle & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.max_tilt_pd0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.max_tilt_pd1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_wrist_wakeup_tilt_pu(const MblMwMetaWearBoard *board, uint16_t angle) { + switch(board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation) { + case MBL_MW_MODULE_ACC_TYPE_BMI270: { + auto lower_8 = angle & 0x00ff; + auto higher_8 = (angle & 0xff00) >> 8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.max_tilt_pu0 = lower_8; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap.max_tilt_pu1 = higher_8; + break; + } + } +} + +void mbl_mw_acc_bmi270_write_wrist_wakeup_config(const MblMwMetaWearBoard* board) { + uint8_t command[15]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_CONFIG), ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.index}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.wrist_wakeup.bitmap; + memcpy(command + 3, &config, sizeof(config)); + SEND_COMMAND; +} + +void mbl_mw_acc_bmi270_enable_wrist_wakeup(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x08, 0x00}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x08, 0x00}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_disable_wrist_wakeup(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x00, 0x08}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x00, 0x08}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_enable_activity_detection(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x04, 0x00}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x04, 0x00}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_disable_activity_detection(const MblMwMetaWearBoard *board) { + uint8_t command1[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_INTERRUPT_ENABLE), 0x00, 0x04}; + send_command(board, command1, sizeof(command1)); + uint8_t command2[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_ENABLE), 0x00, 0x04}; + send_command(board, command2, sizeof(command2)); +} + +void mbl_mw_acc_bmi270_axis_remap(const MblMwMetaWearBoard* board, MblMwAccBoschAxisXyzRemap map, MblMwAccBoschAxisXyzSign sign) { + switch(map) { + case MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_XYZ://[0,1,2] + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis = 2; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_YZX: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis = 2; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis = 0; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_ZXY: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis = 2; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis = 1; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_XZY: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis = 2; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis = 1; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_YXZ: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis = 2; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_REMAP_ZYX: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis = 2; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis = 0; + break; + } + switch(sign) { + case MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_000: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis_sign = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis_sign = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis_sign = 0; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_100: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis_sign = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis_sign = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis_sign = 0; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_110: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis_sign = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis_sign = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis_sign = 0; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_101: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis_sign = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis_sign = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis_sign = 1; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_010: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis_sign = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis_sign = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis_sign = 0; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_011: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis_sign = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis_sign = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis_sign = 1; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_001: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis_sign = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis_sign = 0; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis_sign = 1; + break; + case MBL_MW_ACC_BOSCH_AXIS_XYZ_SIGN_111: + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_x_axis_sign = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_y_axis_sign = 1; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap.map_z_axis_sign = 1; + break; + } + uint8_t command[5]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::FEATURE_CONFIG), ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.index}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->feature_config.axis_remap.bitmap; + memcpy(command + 3, &config, sizeof(config)); + SEND_COMMAND; +} + +void mbl_mw_acc_bmi270_acc_offsets(const MblMwMetaWearBoard* board, uint16_t x_offset, uint16_t y_offset, uint16_t z_offset) { + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->nv_offset.acc_off_en = 1; + + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->nv_offset.off_acc_x = x_offset; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->nv_offset.off_acc_y = y_offset; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->nv_offset.off_acc_z = z_offset; + + uint8_t command[6]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::OFFSET)}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->nv_offset; + memcpy(command + 2, &config, sizeof(config)); + SEND_COMMAND; +} + +void mbl_mw_acc_bmi270_fifo_downs(const MblMwMetaWearBoard* board, uint8_t gyro_downs, uint8_t gyro_data, uint8_t acc_downs, uint8_t acc_data) { + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->fifo_downs.gyr_fifo_downs = gyro_downs; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->fifo_downs.gyr_fifo_filt_data = gyro_data; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->fifo_downs.acc_fifo_downs = acc_downs; + ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->fifo_downs.acc_fifo_filt_data = acc_data; + + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi270Register::DOWNSAMPLING)}; + auto config= ((AccBmi270Config*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->fifo_downs; + memcpy(command + 2, &config, sizeof(config)); + SEND_COMMAND; +} + +void mbl_mw_acc_bosch_enable_orientation_detection(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::ORIENT_INTERRUPT_ENABLE), 1, 0}; + SEND_COMMAND; +} + +void mbl_mw_acc_bosch_disable_orientation_detection(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::ORIENT_INTERRUPT_ENABLE), 0, 1}; + SEND_COMMAND; +} + +void mbl_mw_acc_bosch_start(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::POWER_MODE), 1}; + if (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation == MBL_MW_MODULE_ACC_TYPE_BMI270) { + auto config= (AccBmi270Config*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER); + if (config->acc.us == 0) { + command[2] = 2; + } + } + SEND_COMMAND; +} + +void mbl_mw_acc_bosch_stop(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::POWER_MODE), 0}; + SEND_COMMAND; +} + +void mbl_mw_acc_bosch_enable_acceleration_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::DATA_INTERRUPT_ENABLE), 1, 0}; + SEND_COMMAND; +} + +void mbl_mw_acc_bosch_disable_acceleration_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerBmi160Register::DATA_INTERRUPT_ENABLE), 0, 1}; + SEND_COMMAND; +} + +void create_acc_bosch_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(AccelerometerBmi160Register::DATA_INTERRUPT): + uri << "acceleration"; + if (signal->length() <= 2) { + uri << "[" << (int) (signal->offset >> 1) << "]"; + } + break; + case ORDINAL(AccelerometerBmi160Register::ORIENT_INTERRUPT): + uri << "orientation"; + break; + case ORDINAL(AccelerometerBmi160Register::MOTION_INTERRUPT): + uri << "bosch-motion"; + break; + } +} + +void create_acc_bmi270_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(AccelerometerBmi270Register::DATA_INTERRUPT): + uri << "acceleration"; + if (signal->length() <= 2) { + uri << "[" << (int) (signal->offset >> 1) << "]"; + } + break; + case ORDINAL(AccelerometerBmi270Register::MOTION_INTERRUPT): + uri << "bosch-motion"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch_private.h new file mode 100644 index 0000000..f6bf170 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch_private.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +float bosch_get_data_scale(const MblMwMetaWearBoard *board); + +void free_accelerometer_bosch(MblMwMetaWearBoard *board); +void init_accelerometer_bmi160(MblMwMetaWearBoard *board); +void init_accelerometer_bma255(MblMwMetaWearBoard *board); +void init_accelerometer_bmi270(MblMwMetaWearBoard *board); + +void serialize_accelerometer_bmi160_config(const MblMwMetaWearBoard* board, std::vector& state); +void serialize_accelerometer_bma255_config(const MblMwMetaWearBoard* board, std::vector& state); +void serialize_accelerometer_bmi270_config(const MblMwMetaWearBoard* board, std::vector& state); + +void deserialize_accelerometer_bmi160_config(MblMwMetaWearBoard* board, uint8_t** state_stream); +void deserialize_accelerometer_bma255_config(MblMwMetaWearBoard* board, uint8_t** state_stream); +void deserialize_accelerometer_bmi270_config(MblMwMetaWearBoard* board, uint8_t** state_stream); + +void read_accelerometer_bosch_acceleration_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed); +void create_acc_bosch_uri(const MblMwDataSignal* signal, std::stringstream& uri); +void create_acc_bmi270_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch_register.h new file mode 100644 index 0000000..e99b3e6 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch_register.h @@ -0,0 +1,57 @@ +#pragma once + +enum class AccelerometerBmi160Register : uint8_t { + POWER_MODE = 1, + DATA_INTERRUPT_ENABLE, + DATA_CONFIG, + DATA_INTERRUPT, + DATA_INTERRUPT_CONFIG, + + MOTION_INTERRUPT_ENABLE = 0x9, + MOTION_CONFIG, + MOTION_INTERRUPT, + + TAP_INTERRUPT_ENABLE, + TAP_CONFIG, + TAP_INTERRUPT, + + ORIENT_INTERRUPT_ENABLE = 0xf, + ORIENT_CONFIG, + ORIENT_INTERRUPT, + + /// +#include +#include + +using std::forward_as_tuple; +using std::calloc; +using std::memcpy; +using std::memset; +using std::piecewise_construct; +using std::string; +using std::stringstream; +using std::unordered_map; + +#define CREATE_ACC_SIGNAL_SINGLE(offset) CREATE_ACC_SIGNAL(DataInterpreter::MMA8452Q_ACCELERATION_SINGLE_AXIS, 1, offset) +#define CREATE_ACC_SIGNAL(interpreter, channels, offset) new MblMwDataSignal(MMA8452Q_ACCEL_RESPONSE_HEADER, board, interpreter, \ + FirmwareConverter::MMA8452Q_ACCELERATION, channels, 2, 1, offset) + +const uint8_t MBL_MW_MODULE_ACC_TYPE_MMA8452Q = 0; ///< Constant identifying the MMA8452Q accelerometer type + +const uint8_t MMA8452Q_DEFAULT_CONFIG[]= { + 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x44, 0x84, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}, PACKED_ACC_REVISION= 1; + +const float ORIENTATION_STEPS[4][8] = { + {1.25f, 2.5f, 5, 10, 20, 20, 20, 20}, + {1.25f, 2.5f, 5, 10, 20, 80, 80, 80}, + {1.25f, 2.5f, 2.5f, 2.5f, 2.5f, 2.5f, 2.5f, 2.5f}, + {1.25f, 2.5f, 5, 10, 20, 80, 160, 160} +}; + +const float OS_CUTOFF_FREQS[4][8][4] = { + { + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f }, + { 8.f, 4.f, 2.f, 1.f }, + { 4.f, 2.f, 1.f, 0.5f }, + { 2.f, 1.f, 0.5f, 0.25f }, + { 2.f, 1.f, 0.5f, 0.25f }, + { 2.f, 1.f, 0.5f, 0.25f }, + { 2.f, 1.f, 0.5f, 0.25f } + }, + { + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f }, + { 8.f, 4.f, 2.f, 1.f }, + { 4.f, 2.f, 1.f, 0.5f }, + { 2.f, 1.f, 0.5f, 0.25f }, + { 0.5f, 0.25f, 0.125f, 0.063f }, + { 0.5f, 0.25f, 0.125f, 0.063f }, + { 0.5f, 0.25f, 0.125f, 0.063f } + }, + { + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f }, + { 16.f, 8.f, 4.f, 2.f } + }, + { + { 16.f, 8.f, 4.f, 2.f }, + { 8.f, 4.f, 2.f, 1.f }, + { 4.f, 2.f, 1.f, 0.5f }, + { 2.f, 1.f, 0.5f, 0.25f }, + { 1.f, 0.5f, 0.25f, 0.125f }, + { 0.25f, 0.125f, 0.063f, 0.031f }, + { 0.25f, 0.125f, 0.063f, 0.031f }, + { 0.25f, 0.125f, 0.063f, 0.031f } + } +}; + +struct Mma8452qConfig { + struct { + uint8_t fs:2; + uint8_t :2; + uint8_t hpf_out:1; + uint8_t :3; + uint8_t sel:2; + uint8_t :2; + uint8_t pulse_lpf_en:1; + uint8_t pulse_hpf_en:1; + uint8_t :2; + uint8_t active:1; + uint8_t f_read:1; + uint8_t lnoise:1; + uint8_t dr:3; + uint8_t aslp_rate:2; + uint8_t mods:2; + uint8_t slpe:1; + uint8_t smods:2; + uint8_t :1; + uint8_t rst:1; + uint8_t st:1; + uint8_t aslp_count; + } acc; + struct { + uint8_t :3; + uint8_t xefe:1; + uint8_t yefe:1; + uint8_t zefe:1; + uint8_t oae:1; + uint8_t ele:1; + uint8_t :8; + uint8_t ths:7; + uint8_t dbcntm:1; + uint8_t count; + } ff_mt; + struct { + uint8_t :8; + uint8_t :6; + uint8_t pl_en:1; + uint8_t dbcntm:1; + uint8_t pl_count; + uint8_t zlock:3; + uint8_t :3; + uint8_t bkfr:2; + uint8_t hys:3; + uint8_t pl_ths:5; + } orientation; + struct { + uint8_t xspefe:1; + uint8_t xdpefe:1; + uint8_t yspefe:1; + uint8_t ydpefe:1; + uint8_t zspefe:1; + uint8_t zdpefe:1; + uint8_t ele:1; + uint8_t dpa:1; + uint8_t :8; + uint8_t thsx, thsy, thsz, tmlt, ltcy, wind; + } tap; + struct { + uint8_t hpf_byp:1; + uint8_t xtefe:1; + uint8_t ytefe:1; + uint8_t ztefe:1; + uint8_t ele:1; + uint8_t :3; + uint8_t :8; + uint8_t ths:7; + uint8_t dbcntm:1; + uint8_t transient_count; + } shake; +}; + +const ResponseHeader MMA8452Q_ACCEL_RESPONSE_HEADER(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::DATA_VALUE)), + MMA8452Q_PACKED_ACCEL_RESPONSE_HEADER(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::PACKED_ACC_DATA)), + MMA8452Q_ORIENTATION_RESPONSE_HEADER(MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::ORIENTATION_VALUE)); + +struct AccMma8452qState { + MblMwFnBoardPtrInt read_config_completed; + void *read_config_context; + uint16_t orient_delay; +}; + +static unordered_map states; + +static int32_t received_config_response(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto config = &((Mma8452qConfig*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc; + memcpy(config, response + 2, sizeof(*config)); + + auto callback = states[board].read_config_completed; + auto context = states[board].read_config_context; + states[board].read_config_completed = nullptr; + states[board].read_config_context = nullptr; + callback(context, board, MBL_MW_STATUS_OK); + + return MBL_MW_STATUS_OK; +} + +void init_accelerometer_mma8452q(MblMwMetaWearBoard *board) { + MblMwDataSignal* acc; + + if (board->module_events.count(MMA8452Q_ACCEL_RESPONSE_HEADER)) { + acc = dynamic_cast(board->module_events[MMA8452Q_ACCEL_RESPONSE_HEADER]); + } else { + acc = CREATE_ACC_SIGNAL(DataInterpreter::MMA8452Q_ACCELERATION, 3, 0); + board->module_events[MMA8452Q_ACCEL_RESPONSE_HEADER] = acc; + } + if (!acc->components.size()) { + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(0)); + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(2)); + acc->components.push_back(CREATE_ACC_SIGNAL_SINGLE(4)); + } + + if (!board->module_config.count(MBL_MW_MODULE_ACCELEROMETER)) { + Mma8452qConfig* config= (Mma8452qConfig*) malloc(sizeof(Mma8452qConfig)); + memcpy(config, MMA8452Q_DEFAULT_CONFIG, sizeof(MMA8452Q_DEFAULT_CONFIG)); + + board->module_config[MBL_MW_MODULE_ACCELEROMETER] = config; + } + board->responses[MMA8452Q_ACCEL_RESPONSE_HEADER]= response_handler_data_no_id; + + if (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).revision >= PACKED_ACC_REVISION) { + if (!board->module_events.count(MMA8452Q_PACKED_ACCEL_RESPONSE_HEADER)) { + board->module_events[MMA8452Q_PACKED_ACCEL_RESPONSE_HEADER]= new MblMwDataSignal(MMA8452Q_PACKED_ACCEL_RESPONSE_HEADER, board, + DataInterpreter::MMA8452Q_ACCELERATION, FirmwareConverter::MMA8452Q_ACCELERATION, 3, 2, 1, 0); + } + board->responses[MMA8452Q_PACKED_ACCEL_RESPONSE_HEADER]= response_handler_packed_data; + } + + if (!board->module_events.count(MMA8452Q_ORIENTATION_RESPONSE_HEADER)) { + board->module_events[MMA8452Q_ORIENTATION_RESPONSE_HEADER]= new MblMwDataSignal(MMA8452Q_ORIENTATION_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_ORIENTATION_MMA8452Q, FirmwareConverter::DEFAULT, 1, 1, 0, 0); + } + board->responses[MMA8452Q_ORIENTATION_RESPONSE_HEADER]= response_handler_data_no_id; + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerMma8452qRegister::DATA_CONFIG))), + forward_as_tuple(received_config_response)); + + AccMma8452qState newState = {nullptr, nullptr, 100}; + states.insert({board, newState}); +} + +void free_accelerometer_mma8452q(MblMwMetaWearBoard *board) { + states.erase(board); +} + +void serialize_accelerometer_mma8452q_config(const MblMwMetaWearBoard* board, std::vector& state) { + SERIALIZE_MODULE_CONFIG(Mma8452qConfig, MBL_MW_MODULE_ACCELEROMETER); +} + +void deserialize_accelerometer_mma8452q_config(MblMwMetaWearBoard* board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(Mma8452qConfig, MBL_MW_MODULE_ACCELEROMETER); +} + +MblMwDataSignal* mbl_mw_acc_mma8452q_get_acceleration_data_signal(const MblMwMetaWearBoard *board) { + if (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation != MBL_MW_MODULE_ACC_TYPE_MMA8452Q) { + return nullptr; + } + GET_DATA_SIGNAL(MMA8452Q_ACCEL_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_acc_mma8452q_get_high_freq_acceleration_data_signal(const MblMwMetaWearBoard *board) { + return mbl_mw_acc_mma8452q_get_packed_acceleration_data_signal(board); +} + +MblMwDataSignal* mbl_mw_acc_mma8452q_get_packed_acceleration_data_signal(const MblMwMetaWearBoard *board) { + if (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation != MBL_MW_MODULE_ACC_TYPE_MMA8452Q) { + return nullptr; + } + GET_DATA_SIGNAL(MMA8452Q_PACKED_ACCEL_RESPONSE_HEADER); +} + +void mbl_mw_acc_mma8452q_set_odr(MblMwMetaWearBoard *board, MblMwAccMma8452qOdr odr) { + ((Mma8452qConfig*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc.dr= odr; +} + +void mbl_mw_acc_mma8452q_set_range(MblMwMetaWearBoard *board, MblMwAccMma8452qRange range) { + ((Mma8452qConfig*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc.fs= range; +} + +void mbl_mw_acc_mma8452q_set_high_pass_cutoff(MblMwMetaWearBoard *board, float frequency) { + auto config = ((Mma8452qConfig*)board->module_config.at(MBL_MW_MODULE_ACCELEROMETER)); + if (frequency != 0) { + // 'size' parameter is the 3rd index of OS_CUTOFF_FREQS definition + config->acc.sel = closest_index(OS_CUTOFF_FREQS[config->acc.mods][config->acc.dr], 4, frequency); + config->acc.hpf_out = 1; + } else { + config->acc.hpf_out = 0; + } +} + +void mbl_mw_acc_mma8452q_start(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::GLOBAL_ENABLE), 1}; + SEND_COMMAND; +} + +void mbl_mw_acc_mma8452q_stop(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::GLOBAL_ENABLE), 0}; + SEND_COMMAND; +} + +void mbl_mw_acc_mma8452q_enable_acceleration_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::DATA_ENABLE), 1}; + SEND_COMMAND; +} + +void mbl_mw_acc_mma8452q_disable_acceleration_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::DATA_ENABLE), 0}; + SEND_COMMAND; +} + +void mbl_mw_acc_mma8452q_write_acceleration_config(const MblMwMetaWearBoard *board) { + uint8_t command[7]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::DATA_CONFIG)}; + + auto config = ((Mma8452qConfig*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER))->acc; + memcpy(command + 2, &config, sizeof(config)); + + SEND_COMMAND; +} + +void read_accelerometer_mma8452q_acceleration_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed) { + states[board].read_config_context = context; + states[board].read_config_completed = completed; + + uint8_t command[2]= {MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerMma8452qRegister::DATA_CONFIG))}; + SEND_COMMAND; +} + +void create_acc_mma8452q_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(AccelerometerMma8452qRegister::DATA_VALUE): + uri << "acceleration"; + if (signal->length() <= 2) { + uri << "[" << (int) (signal->offset >> 1) << "]"; + } + break; + case ORDINAL(AccelerometerMma8452qRegister::ORIENTATION_VALUE): + uri << "orientation"; + break; + } +} + +MblMwDataSignal* mbl_mw_acc_mma8452q_get_orientation_detection_data_signal(const MblMwMetaWearBoard* board) { + if (board->module_info.at(MBL_MW_MODULE_ACCELEROMETER).implementation != MBL_MW_MODULE_ACC_TYPE_MMA8452Q) { + return nullptr; + } + GET_DATA_SIGNAL(MMA8452Q_ORIENTATION_RESPONSE_HEADER); +} + +void mbl_mw_acc_mma8452q_set_orientation_delay(MblMwMetaWearBoard *board, uint16_t delay) { + states[board].orient_delay = delay; +} + +void mbl_mw_acc_mma8452q_enable_orientation_detection(const MblMwMetaWearBoard *board) { + auto config = (Mma8452qConfig*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER); + config->orientation.pl_count = static_cast(states[board].orient_delay / ORIENTATION_STEPS[config->acc.mods][config->acc.dr]); + config->orientation.pl_en = 1; + + uint8_t config_cmd[7] = { MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::ORIENTATION_CONFIG) }; + memcpy(config_cmd + 2, &config->orientation, sizeof(config->orientation)); + send_command(board, config_cmd, sizeof(config_cmd)); + + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::ORIENTATION_ENABLE), 1}; + SEND_COMMAND; +} + +void mbl_mw_acc_mma8452q_disable_orientation_detection(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::ORIENTATION_ENABLE), 0}; + SEND_COMMAND; + + auto config = (Mma8452qConfig*) board->module_config.at(MBL_MW_MODULE_ACCELEROMETER); + config->orientation.pl_count = 0; + config->orientation.pl_en = 0; + + uint8_t config_cmd[7] = { MBL_MW_MODULE_ACCELEROMETER, ORDINAL(AccelerometerMma8452qRegister::ORIENTATION_CONFIG) }; + memcpy(config_cmd + 2, &config->orientation, sizeof(config->orientation)); + send_command(board, config_cmd, sizeof(config_cmd)); +} \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q_private.h new file mode 100644 index 0000000..26ebf5c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q_private.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +void init_accelerometer_mma8452q(MblMwMetaWearBoard *board); +void free_accelerometer_mma8452q(MblMwMetaWearBoard *board); +void serialize_accelerometer_mma8452q_config(const MblMwMetaWearBoard* board, std::vector& state); +void deserialize_accelerometer_mma8452q_config(MblMwMetaWearBoard* board, uint8_t** state_stream); + +void read_accelerometer_mma8452q_acceleration_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed); +void create_acc_mma8452q_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q_register.h new file mode 100644 index 0000000..2e43a44 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q_register.h @@ -0,0 +1,21 @@ +#pragma once + +enum class AccelerometerMma8452qRegister : uint8_t { + GLOBAL_ENABLE = 1, + DATA_ENABLE, + DATA_CONFIG, + DATA_VALUE, + MOVEMENT_ENABLE, + MOVEMENT_CONFIG, + MOVEMENT_VALUE, + ORIENTATION_ENABLE, + ORIENTATION_CONFIG, + ORIENTATION_VALUE, + PULSE_ENABLE, + PULSE_CONFIG, + PULSE_STATUS, + SHAKE_ENABLE, + SHAKE_CONFIG, + SHAKE_STATUS, + PACKED_ACC_DATA= 0x12 +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_private.h new file mode 100644 index 0000000..501764f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_private.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +void init_accelerometer_module(MblMwMetaWearBoard *board); +void free_accelerometer_module(MblMwMetaWearBoard *board); +void serialize_accelerometer_config(const MblMwMetaWearBoard *board, std::vector& state); +void deserialize_accelerometer_config(MblMwMetaWearBoard *board, uint8_t** state_stream); +void create_acc_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329.cpp new file mode 100644 index 0000000..a018903 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329.cpp @@ -0,0 +1,107 @@ +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/module.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include "metawear/sensor/ambientlight_ltr329.h" +#include "ambientlight_ltr329_private.h" +#include "ambientlight_ltr329_register.h" +#include "utils.h" + +#include +#include + +using std::forward_as_tuple; +using std::malloc; +using std::memcpy; +using std::memset; +using std::piecewise_construct; +using std::stringstream; + +const ResponseHeader LTR329_ILLUMINANCE_RESPONSE_HEADER(MBL_MW_MODULE_AMBIENT_LIGHT, ORDINAL(AmbientLightLtr329Register::OUTPUT)); + +struct Ltr329Config { + uint8_t:2; + uint8_t als_gain:3; + uint8_t:3; + uint8_t als_measurement_rate:3; + uint8_t als_integration_time:3; + uint8_t:2; +}; + +void init_ambient_light_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_AMBIENT_LIGHT) && board->module_info.at(MBL_MW_MODULE_AMBIENT_LIGHT).present) { + if (!board->module_config.count(MBL_MW_MODULE_AMBIENT_LIGHT)) { + Ltr329Config* new_config = (Ltr329Config*)malloc(sizeof(Ltr329Config)); + + memset(new_config, 0, sizeof(Ltr329Config)); + new_config->als_measurement_rate = MBL_MW_ALS_LTR329_RATE_500ms; + board->module_config.emplace(MBL_MW_MODULE_AMBIENT_LIGHT, new_config); + } + + if (!board->module_events.count(LTR329_ILLUMINANCE_RESPONSE_HEADER)) { + board->module_events[LTR329_ILLUMINANCE_RESPONSE_HEADER] = new MblMwDataSignal(LTR329_ILLUMINANCE_RESPONSE_HEADER, + board, DataInterpreter::UINT32, 1, 4, 0, 0); + } + board->responses[LTR329_ILLUMINANCE_RESPONSE_HEADER]= response_handler_data_no_id; + } +} + +void serialize_ambient_light_config(const MblMwMetaWearBoard *board, std::vector& state) { + SERIALIZE_MODULE_CONFIG(Ltr329Config, MBL_MW_MODULE_AMBIENT_LIGHT); +} + +void deserialize_ambient_light_config(MblMwMetaWearBoard *board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(Ltr329Config, MBL_MW_MODULE_AMBIENT_LIGHT); +} + +MblMwDataSignal* mbl_mw_als_ltr329_get_illuminance_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(LTR329_ILLUMINANCE_RESPONSE_HEADER); +} + +void mbl_mw_als_ltr329_set_gain(MblMwMetaWearBoard *board, MblMwAlsLtr329Gain gain) { + switch(gain) { + case MBL_MW_ALS_LTR329_GAIN_48X: + case MBL_MW_ALS_LTR329_GAIN_96X: + ((Ltr329Config*) board->module_config.at(MBL_MW_MODULE_AMBIENT_LIGHT))->als_gain= gain + 2; + break; + default: + ((Ltr329Config*) board->module_config.at(MBL_MW_MODULE_AMBIENT_LIGHT))->als_gain= gain; + break; + } +} + +void mbl_mw_als_ltr329_set_integration_time(MblMwMetaWearBoard *board, MblMwAlsLtr329IntegrationTime integration_time) { + ((Ltr329Config*) board->module_config.at(MBL_MW_MODULE_AMBIENT_LIGHT))->als_integration_time= integration_time; +} + +void mbl_mw_als_ltr329_set_measurement_rate(MblMwMetaWearBoard *board, MblMwAlsLtr329MeasurementRate measurement_rate) { + ((Ltr329Config*) board->module_config.at(MBL_MW_MODULE_AMBIENT_LIGHT))->als_measurement_rate= measurement_rate; +} + +void mbl_mw_als_ltr329_write_config(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_AMBIENT_LIGHT, ORDINAL(AmbientLightLtr329Register::CONFIG)}; + memcpy(command + 2, board->module_config.at(MBL_MW_MODULE_AMBIENT_LIGHT), sizeof(Ltr329Config)); + SEND_COMMAND; +} + +void mbl_mw_als_ltr329_start(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_AMBIENT_LIGHT, ORDINAL(AmbientLightLtr329Register::ENABLE), 1}; + SEND_COMMAND; +} + +void mbl_mw_als_ltr329_stop(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_AMBIENT_LIGHT, ORDINAL(AmbientLightLtr329Register::ENABLE), 0}; + SEND_COMMAND; +} + +void create_als_uri(const MblMwDataSignal* signal, std::stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(AmbientLightLtr329Register::OUTPUT): + uri << "illuminance"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329_private.h new file mode 100644 index 0000000..56112b1 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329_private.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +void init_ambient_light_module(MblMwMetaWearBoard *board); +void serialize_ambient_light_config(const MblMwMetaWearBoard *board, std::vector& state); +void deserialize_ambient_light_config(MblMwMetaWearBoard *board, uint8_t** state_stream); +void create_als_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329_register.h new file mode 100644 index 0000000..b8dca48 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329_register.h @@ -0,0 +1,7 @@ +#pragma once + +enum class AmbientLightLtr329Register : uint8_t { + ENABLE = 1, + CONFIG, + OUTPUT, +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch.cpp new file mode 100644 index 0000000..1d86510 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch.cpp @@ -0,0 +1,158 @@ +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include "metawear/sensor/barometer_bosch.h" +#include "barometer_bosch_private.h" +#include "barometer_bosch_register.h" +#include "utils.h" + +#include +#include + +using std::calloc; +using std::forward_as_tuple; +using std::memcpy; +using std::piecewise_construct; +using std::vector; + +const uint8_t MBL_MW_MODULE_BARO_TYPE_BMP280 = 0; ///< Constant identifying the BMP280 barometer module type +const uint8_t MBL_MW_MODULE_BARO_TYPE_BME280 = 1; ///< Constant identifying the BME280 barometer module type + +const vector BMP280_STANDBY_VALUES= {0.5f, 62.5f, 125.f, 250.f, 500.f, 1000.f, 2000.f, 4000.f}, + BME280_STANDBY_VALUES= {0.5f, 62.5f, 125.f, 250.f, 500.f, 1000.f, 10.f, 20.f}; + +const ResponseHeader BARO_PRESSURE_RESPONSE_HEADER(MBL_MW_MODULE_BAROMETER, ORDINAL(BarometerBmp280Register::PRESSURE)), + BARO_ALTITUDE_RESPONSE_HEADER(MBL_MW_MODULE_BAROMETER, ORDINAL(BarometerBmp280Register::ALTITUDE)), + BARO_PRESSURE_READ_RESPONSE_HEADER(MBL_MW_MODULE_BAROMETER, READ_REGISTER(ORDINAL(BarometerBmp280Register::PRESSURE))); + +struct BoschBaroConfig { + uint8_t:2; + uint8_t pressure_oversampling:3; + uint8_t temperature_oversampling:3; + uint8_t:2; + uint8_t iir_filter:3; + uint8_t standby_time:3; +}; + +void init_barometer_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_BAROMETER) && board->module_info.at(MBL_MW_MODULE_BAROMETER).present) { + if (!board->module_config.count(MBL_MW_MODULE_BAROMETER)) { + BoschBaroConfig* new_config = (BoschBaroConfig*)calloc(1, sizeof(BoschBaroConfig)); + + new_config->pressure_oversampling = MBL_MW_BARO_BOSCH_OVERSAMPLING_STANDARD; + new_config->iir_filter = MBL_MW_BARO_BOSCH_IIR_FILTER_OFF; + new_config->standby_time = 0; ///< Set standby time to 0.5ms, which is enum 0 for both bmp280 and bme280 + new_config->temperature_oversampling = MBL_MW_BARO_BOSCH_OVERSAMPLING_ULTRA_LOW_POWER; + + board->module_config.emplace(MBL_MW_MODULE_BAROMETER, new_config); + } + + if (!board->module_events.count(BARO_PRESSURE_RESPONSE_HEADER)) { + board->module_events[BARO_PRESSURE_RESPONSE_HEADER] = new MblMwDataSignal(BARO_PRESSURE_RESPONSE_HEADER, board, + DataInterpreter::BOSCH_PRESSURE, FirmwareConverter::BOSCH_BAROMETER, 1, 4, 0, 0); + } + board->responses[BARO_PRESSURE_RESPONSE_HEADER]= response_handler_data_no_id; + + if (!board->module_events.count(BARO_ALTITUDE_RESPONSE_HEADER)) { + board->module_events[BARO_ALTITUDE_RESPONSE_HEADER] = new MblMwDataSignal(BARO_ALTITUDE_RESPONSE_HEADER, board, + DataInterpreter::BOSCH_ALTITUDE, FirmwareConverter::BOSCH_BAROMETER, 1, 4, 1, 0); + } + board->responses[BARO_ALTITUDE_RESPONSE_HEADER]= response_handler_data_no_id; + + if (!board->module_events.count(BARO_PRESSURE_READ_RESPONSE_HEADER)) { + board->module_events[BARO_PRESSURE_READ_RESPONSE_HEADER] = new MblMwDataSignal(BARO_PRESSURE_READ_RESPONSE_HEADER, board, + DataInterpreter::BOSCH_PRESSURE, FirmwareConverter::BOSCH_BAROMETER, 1, 4, 0, 0); + } + board->responses[BARO_PRESSURE_READ_RESPONSE_HEADER]= response_handler_data_no_id; + } +} + + +void serialize_barometer_config(const MblMwMetaWearBoard *board, vector& state) { + SERIALIZE_MODULE_CONFIG(BoschBaroConfig, MBL_MW_MODULE_BAROMETER); +} + +void deserialize_barometer_config(MblMwMetaWearBoard *board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(BoschBaroConfig, MBL_MW_MODULE_BAROMETER); +} + +MblMwDataSignal* mbl_mw_baro_bosch_get_pressure_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(BARO_PRESSURE_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_baro_bosch_get_pressure_read_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(BARO_PRESSURE_READ_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_baro_bosch_get_altitude_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(BARO_ALTITUDE_RESPONSE_HEADER); +} + +void mbl_mw_baro_bosch_set_oversampling(MblMwMetaWearBoard *board, MblMwBaroBoschOversampling oversampling) { + auto config= (BoschBaroConfig*) board->module_config.at(MBL_MW_MODULE_BAROMETER); + + config->pressure_oversampling= oversampling; + if (oversampling == MBL_MW_BARO_BOSCH_OVERSAMPLING_ULTRA_HIGH) { + config->temperature_oversampling= MBL_MW_BARO_BOSCH_OVERSAMPLING_LOW_POWER; + } +} + +void mbl_mw_baro_bosch_set_iir_filter(MblMwMetaWearBoard *board, MblMwBaroBoschIirFilter iir_filter) { + ((BoschBaroConfig*) board->module_config.at(MBL_MW_MODULE_BAROMETER))->iir_filter= iir_filter; +} + +void mbl_mw_baro_bmp280_set_standby_time(MblMwMetaWearBoard *board, MblMwBaroBmp280StandbyTime standby_time) { + ((BoschBaroConfig*) board->module_config.at(MBL_MW_MODULE_BAROMETER))->standby_time= standby_time; +} + +void mbl_mw_baro_bme280_set_standby_time(MblMwMetaWearBoard *board, MblMwBaroBme280StandbyTime standby_time) { + ((BoschBaroConfig*) board->module_config.at(MBL_MW_MODULE_BAROMETER))->standby_time= standby_time; +} + +float mbl_mw_baro_bosch_set_standby_time(MblMwMetaWearBoard *board, float standby_time_ms) { + uint8_t index; + + switch (board->module_info.at(MBL_MW_MODULE_BAROMETER).implementation) { + case MBL_MW_MODULE_BARO_TYPE_BMP280: + index= closest_index(BMP280_STANDBY_VALUES, standby_time_ms); + mbl_mw_baro_bmp280_set_standby_time(board, (MblMwBaroBmp280StandbyTime) index); + return BMP280_STANDBY_VALUES[index]; + case MBL_MW_MODULE_BARO_TYPE_BME280: + index= closest_index(BME280_STANDBY_VALUES, standby_time_ms); + mbl_mw_baro_bme280_set_standby_time(board, (MblMwBaroBme280StandbyTime) index); + return BME280_STANDBY_VALUES[index]; + default: + return -1; + } +} + +void mbl_mw_baro_bosch_write_config(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_BAROMETER, ORDINAL(BarometerBmp280Register::CONFIG)}; + memcpy(command + 2, board->module_config.at(MBL_MW_MODULE_BAROMETER), sizeof(BoschBaroConfig)); + SEND_COMMAND; +} + +void mbl_mw_baro_bosch_start(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_BAROMETER, ORDINAL(BarometerBmp280Register::CYCLIC), 1, 1}; + SEND_COMMAND; +} + +void mbl_mw_baro_bosch_stop(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_BAROMETER, ORDINAL(BarometerBmp280Register::CYCLIC), 0, 0}; + SEND_COMMAND; +} + +void create_barometer_uri(const MblMwDataSignal* signal, std::stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(BarometerBmp280Register::PRESSURE): + uri << "pressure"; + break; + case ORDINAL(BarometerBmp280Register::ALTITUDE): + uri << "altitude"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch_private.h new file mode 100644 index 0000000..52b0d5d --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch_private.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +#include "metawear/core/metawearboard_fwd.h" + +void init_barometer_module(MblMwMetaWearBoard *board); +void serialize_barometer_config(const MblMwMetaWearBoard *board, std::vector& state); +void deserialize_barometer_config(MblMwMetaWearBoard *board, uint8_t** state_stream); +void create_barometer_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch_register.h new file mode 100644 index 0000000..30916dd --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch_register.h @@ -0,0 +1,8 @@ +#pragma once + +enum class BarometerBmp280Register : uint8_t { + PRESSURE = 1, + ALTITUDE, + CONFIG, + CYCLIC +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725.cpp new file mode 100644 index 0000000..cfc0866 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725.cpp @@ -0,0 +1,104 @@ +#include "metawear/sensor/colordetector_tcs34725.h" +#include "colordetector_tcs34725_private.h" +#include "colordetector_tcs34725_register.h" +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include +#include +#include + +using std::calloc; +using std::stringstream; + +#define CREATE_ADC_SIGNAL_SINGLE(offset) CREATE_ADC_SIGNAL(DataInterpreter::UINT32, 1, offset) +#define CREATE_ADC_SIGNAL(interpreter, channels, offset) new MblMwDataSignal(CD_TCS34725_ADC_RESPONSE_HEADER, board, interpreter, \ + FirmwareConverter::DEFAULT, channels, 2, 0, offset) + +const ResponseHeader CD_TCS34725_ADC_RESPONSE_HEADER(MBL_MW_MODULE_COLOR_DETECTOR, READ_REGISTER(ORDINAL(ColorDetectorTcs34725Register::RGB_COLOR))); + +struct Tcs34725Config { + uint8_t integration_time; + uint8_t gain:2; + uint8_t :6; + uint8_t illuminator; +}; + +void init_colordetector_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_COLOR_DETECTOR) && board->module_info.at(MBL_MW_MODULE_COLOR_DETECTOR).present) { + if (!board->module_config.count(MBL_MW_MODULE_COLOR_DETECTOR)) { + Tcs34725Config* new_config = (Tcs34725Config*)calloc(1, sizeof(Tcs34725Config)); + new_config->integration_time = 0xff; + board->module_config.emplace(MBL_MW_MODULE_COLOR_DETECTOR, new_config); + } + + MblMwDataSignal* adc; + if (board->module_events.count(CD_TCS34725_ADC_RESPONSE_HEADER)) { + adc = dynamic_cast(board->module_events[CD_TCS34725_ADC_RESPONSE_HEADER]); + } else { + adc = CREATE_ADC_SIGNAL(DataInterpreter::TCS34725_COLOR_ADC, 4, 0); + board->module_events[CD_TCS34725_ADC_RESPONSE_HEADER] = adc; + } + + if (!adc->components.size()) { + adc->components.push_back(CREATE_ADC_SIGNAL_SINGLE(0)); + adc->components.push_back(CREATE_ADC_SIGNAL_SINGLE(2)); + adc->components.push_back(CREATE_ADC_SIGNAL_SINGLE(4)); + adc->components.push_back(CREATE_ADC_SIGNAL_SINGLE(6)); + } + + board->responses[CD_TCS34725_ADC_RESPONSE_HEADER]= response_handler_data_no_id; + } +} + +void serialize_colordetector_config(const MblMwMetaWearBoard *board, std::vector& state) { + SERIALIZE_MODULE_CONFIG(Tcs34725Config, MBL_MW_MODULE_COLOR_DETECTOR); +} + +void deserialize_colordetector_config(MblMwMetaWearBoard *board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(Tcs34725Config, MBL_MW_MODULE_COLOR_DETECTOR); +} + +MblMwDataSignal* mbl_mw_cd_tcs34725_get_adc_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(CD_TCS34725_ADC_RESPONSE_HEADER); +} + +void mbl_mw_cd_tcs34725_set_integration_time(MblMwMetaWearBoard *board, float time) { + ((Tcs34725Config*) board->module_config.at(MBL_MW_MODULE_COLOR_DETECTOR))->integration_time= (uint8_t) (256.f - time / 2.4f); +} + +void mbl_mw_cd_tcs34725_set_gain(MblMwMetaWearBoard *board, MblMwColorDetectorTcs34725Gain gain) { + ((Tcs34725Config*) board->module_config.at(MBL_MW_MODULE_COLOR_DETECTOR))->gain= gain; +} + +void mbl_mw_cd_tcs34725_enable_illuminator_led(MblMwMetaWearBoard *board) { + ((Tcs34725Config*) board->module_config.at(MBL_MW_MODULE_COLOR_DETECTOR))->illuminator= 1; +} + +void mbl_mw_cd_tcs34725_disable_illuminator_led(MblMwMetaWearBoard *board) { + ((Tcs34725Config*) board->module_config.at(MBL_MW_MODULE_COLOR_DETECTOR))->illuminator= 0; +} + +void mbl_mw_cd_tcs34725_write_config(const MblMwMetaWearBoard *board) { + uint8_t command[5]= { MBL_MW_MODULE_COLOR_DETECTOR, ORDINAL(ColorDetectorTcs34725Register::MODE) }; + memcpy(command + 2, board->module_config.at(MBL_MW_MODULE_COLOR_DETECTOR), sizeof(Tcs34725Config)); + + SEND_COMMAND; +} + +void create_colordetector_uri(const MblMwDataSignal* signal, std::stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(ColorDetectorTcs34725Register::RGB_COLOR): + uri << "color"; + if (signal->length() <= 2) { + uri << "[" << (int) (signal->offset >> 1) << "]"; + } + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725_private.h new file mode 100644 index 0000000..34415cc --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725_private.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +void init_colordetector_module(MblMwMetaWearBoard *board); +void serialize_colordetector_config(const MblMwMetaWearBoard *board, std::vector& state); +void deserialize_colordetector_config(MblMwMetaWearBoard *board, uint8_t** state_stream); +void create_colordetector_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725_register.h new file mode 100644 index 0000000..54ccf5f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725_register.h @@ -0,0 +1,6 @@ +#pragma once + +enum class ColorDetectorTcs34725Register : uint8_t { + RGB_COLOR= 1, + MODE +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance.cpp new file mode 100644 index 0000000..8120188 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance.cpp @@ -0,0 +1,50 @@ +#include + +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/register.h" + +#include "metawear/sensor/conductance.h" +#include "conductance_private.h" +#include "conductance_register.h" + +using std::forward_as_tuple; +using std::piecewise_construct; + +void init_conductance_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_CONDUCTANCE) && board->module_info.at(MBL_MW_MODULE_CONDUCTANCE).present) { + uint8_t num_channels = mbl_mw_conductance_get_num_channels(board); + for(uint8_t channel = 0; channel < num_channels; channel++) { + ResponseHeader header(MBL_MW_MODULE_CONDUCTANCE, READ_REGISTER(ORDINAL(ConductanceRegister::CONDUCTANCE)), channel); + if (!board->module_events.count(header)) { + board->module_events[header] = new MblMwDataSignal(header, board, DataInterpreter::UINT32, + FirmwareConverter::DEFAULT, 1, 4, 0, 0); + } + } + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_CONDUCTANCE, READ_REGISTER(ORDINAL(ConductanceRegister::CONDUCTANCE))), + forward_as_tuple(response_handler_data_with_id)); + } +} + +MblMwDataSignal* mbl_mw_conductance_get_data_signal(const MblMwMetaWearBoard *board, uint8_t channel) { + ResponseHeader header(MBL_MW_MODULE_CONDUCTANCE, READ_REGISTER(ORDINAL(ConductanceRegister::CONDUCTANCE)), channel); + return board->module_events.count(header) ? dynamic_cast(board->module_events.at(header)) : nullptr; +} + +uint8_t mbl_mw_conductance_get_num_channels(const MblMwMetaWearBoard *board) { + return ORDINAL(board->module_info.at(MBL_MW_MODULE_CONDUCTANCE).extra[0]); +} + +void mbl_mw_conductance_calibrate(const MblMwMetaWearBoard *board) { + uint8_t command[2]= {MBL_MW_MODULE_CONDUCTANCE, ORDINAL(ConductanceRegister::CALIBRATE)}; + SEND_COMMAND; +} + +void mbl_mw_conductance_set_range(MblMwMetaWearBoard *board, MblMwConductanceRange range) { + uint8_t command[3]= {MBL_MW_MODULE_CONDUCTANCE, ORDINAL(ConductanceRegister::MODE), ORDINAL(range)}; + SEND_COMMAND; +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance_private.h new file mode 100644 index 0000000..b2b115c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance_private.h @@ -0,0 +1,5 @@ +#pragma once + +#include "metawear/core/metawearboard_fwd.h" + +void init_conductance_module(MblMwMetaWearBoard *board); diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance_register.h new file mode 100644 index 0000000..c8b7e6f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance_register.h @@ -0,0 +1,7 @@ +#pragma once + +enum class ConductanceRegister : uint8_t { + CONDUCTANCE = 1, + CALIBRATE, + MODE +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio.cpp new file mode 100644 index 0000000..9ab37cb --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio.cpp @@ -0,0 +1,172 @@ +#include "metawear/sensor/gpio.h" +#include "gpio_private.h" +#include "gpio_register.h" +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" + +#include + +using std::forward_as_tuple; +using std::memcpy; +using std::piecewise_construct; +using std::stringstream; + +static MblMwGpioAnalogReadParameters default_read_parameters= {0xff, 0xff, 0xff, 0x00}; +const uint8_t ENHANCED_ANALOG_REVISION= 2; + +MblMwGpioPinNotifySignal::MblMwGpioPinNotifySignal(ResponseHeader header, MblMwMetaWearBoard* owner) : + MblMwDataSignal(header, owner, DataInterpreter::UINT32, 1, 1, 0, 0) { +} + +MblMwGpioPinNotifySignal::MblMwGpioPinNotifySignal(uint8_t** state_stream, MblMwMetaWearBoard *owner) : MblMwDataSignal(state_stream, owner) { +} + +void MblMwGpioPinNotifySignal::unsubscribe() { + +} + +MblMwGpioAnalogSignal::MblMwGpioAnalogSignal(ResponseHeader header, MblMwMetaWearBoard* owner) : + MblMwDataSignal(header, owner, DataInterpreter::UINT32, 1, 2, 0, 0) { +} + +MblMwGpioAnalogSignal::MblMwGpioAnalogSignal(uint8_t** state_stream, MblMwMetaWearBoard *owner) : MblMwDataSignal(state_stream, owner) { +} + +void MblMwGpioAnalogSignal::read() const { + if (owner->module_info.at(MBL_MW_MODULE_GPIO).revision < ENHANCED_ANALOG_REVISION) { + MblMwDataSignal::read(); + } else { + read(&default_read_parameters); + } +} + +void MblMwGpioAnalogSignal::read(const void* parameters) const { + if (owner->module_info.at(MBL_MW_MODULE_GPIO).revision < ENHANCED_ANALOG_REVISION) { + MblMwDataSignal::read(); + } else { + uint8_t command[7]= { MBL_MW_MODULE_GPIO, header.register_id, header.data_id }; + const MblMwGpioAnalogReadParameters* read_params= (const MblMwGpioAnalogReadParameters*) parameters; + + command[3]= read_params->pullup_pin; + command[4]= read_params->pulldown_pin; + command[5]= read_params->delay_us >> 2; + command[6]= read_params->virtual_pin; + SEND_COMMAND_BOARD(owner); + } +} + +void init_gpio_module(MblMwMetaWearBoard *board) { + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_GPIO, READ_REGISTER(ORDINAL(GpioRegister::READ_AI_ABS_REF))), + forward_as_tuple(response_handler_data_with_id)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_GPIO, READ_REGISTER(ORDINAL(GpioRegister::READ_AI_ADC))), + forward_as_tuple(response_handler_data_with_id)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_GPIO, READ_REGISTER(ORDINAL(GpioRegister::READ_DI))), + forward_as_tuple(response_handler_data_with_id)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_GPIO, ORDINAL(GpioRegister::PIN_CHANGE_NOTIFY)), + forward_as_tuple(response_handler_data_with_id)); +} + +MblMwDataSignal* mbl_mw_gpio_get_analog_input_data_signal(MblMwMetaWearBoard* board, uint8_t pin, MblMwGpioAnalogReadMode mode) { + GpioRegister analogReadRegister; + + switch (mode) { + case MBL_MW_GPIO_ANALOG_READ_MODE_ABS_REF: + analogReadRegister = GpioRegister::READ_AI_ABS_REF; + break; + case MBL_MW_GPIO_ANALOG_READ_MODE_ADC: + analogReadRegister = GpioRegister::READ_AI_ADC; + break; + default: + return nullptr; + } + + ResponseHeader header(MBL_MW_MODULE_GPIO, READ_REGISTER(ORDINAL(analogReadRegister)), pin); + if (!board->module_events.count(header)) { + board->module_events[header]= new MblMwGpioAnalogSignal(header, board); + } + + return dynamic_cast(board->module_events.at(header)); +} + +MblMwDataSignal* mbl_mw_gpio_get_digital_input_data_signal(MblMwMetaWearBoard* board, uint8_t pin) { + ResponseHeader header(MBL_MW_MODULE_GPIO, READ_REGISTER(ORDINAL(GpioRegister::READ_DI)), pin); + + if (!board->module_events.count(header)) { + board->module_events[header]= new MblMwDataSignal(header, board, DataInterpreter::UINT32, 1, 1, 0, 0); + } + return dynamic_cast(board->module_events.at(header)); +} + +MblMwDataSignal* mbl_mw_gpio_get_pin_monitor_data_signal(MblMwMetaWearBoard* board, uint8_t pin) { + ResponseHeader header(MBL_MW_MODULE_GPIO, ORDINAL(GpioRegister::PIN_CHANGE_NOTIFY), pin); + + if (board->module_events.count(header) == 0) { + board->module_events[header]= new MblMwGpioPinNotifySignal(header, board); + } + + return dynamic_cast(board->module_events.at(header)); +} + +void mbl_mw_gpio_set_pull_mode(const MblMwMetaWearBoard* board, uint8_t pin, MblMwGpioPullMode mode) { + uint8_t command[3]= {MBL_MW_MODULE_GPIO, 0, pin}; + + switch(mode) { + case MBL_MW_GPIO_PULL_MODE_UP: + command[1]= ORDINAL(GpioRegister::PULL_UP_DI); + send_command(board, command, sizeof(command)); + break; + case MBL_MW_GPIO_PULL_MODE_DOWN: + command[1]= ORDINAL(GpioRegister::PULL_DOWN_DI); + send_command(board, command, sizeof(command)); + break; + case MBL_MW_GPIO_PULL_MODE_NONE: + command[1]= ORDINAL(GpioRegister::NO_PULL_DI); + send_command(board, command, sizeof(command)); + break; + } +} + +void mbl_mw_gpio_set_digital_output(const MblMwMetaWearBoard* board, uint8_t pin) { + uint8_t command[3]= {MBL_MW_MODULE_GPIO, ORDINAL(GpioRegister::SET_DO), pin}; + send_command(board, command, sizeof(command)); +} + +void mbl_mw_gpio_clear_digital_output(const MblMwMetaWearBoard* board, uint8_t pin) { + uint8_t command[3]= {MBL_MW_MODULE_GPIO, ORDINAL(GpioRegister::CLEAR_DO), pin}; + send_command(board, command, sizeof(command)); +} + +void mbl_mw_gpio_set_pin_change_type(const MblMwMetaWearBoard* board, uint8_t pin, MblMwGpioPinChangeType type) { + uint8_t command[4]= {MBL_MW_MODULE_GPIO, ORDINAL(GpioRegister::PIN_CHANGE), pin, (uint8_t) type}; + send_command(board, command, sizeof(command)); +} + +void mbl_mw_gpio_start_pin_monitoring(const MblMwMetaWearBoard* board, uint8_t pin) { + uint8_t command[4]= {MBL_MW_MODULE_GPIO, ORDINAL(GpioRegister::PIN_CHANGE_NOTIFY_ENABLE), pin, 1}; + send_command(board, command, sizeof(command)); +} + +void mbl_mw_gpio_stop_pin_monitoring(const MblMwMetaWearBoard* board, uint8_t pin) { + uint8_t command[4]= {MBL_MW_MODULE_GPIO, ORDINAL(GpioRegister::PIN_CHANGE_NOTIFY_ENABLE), pin, 0}; + send_command(board, command, sizeof(command)); +} + +void create_gpio_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(GpioRegister::READ_AI_ABS_REF): + uri << "abs-ref[" << (int) signal->header.data_id << "]"; + break; + case ORDINAL(GpioRegister::READ_AI_ADC): + uri << "adc[" << (int) signal->header.data_id << "]"; + break; + case ORDINAL(GpioRegister::READ_DI): + uri << "digital[" << (int) signal->header.data_id << "]"; + break; + case ORDINAL(GpioRegister::PIN_CHANGE_NOTIFY): + uri << "pin-monitor[" << (int) signal->header.data_id << "]"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio_private.h new file mode 100644 index 0000000..1de85e9 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio_private.h @@ -0,0 +1,23 @@ +#pragma once + +#include "metawear/core/cpp/datasignal_private.h" + +#include + +struct MblMwGpioPinNotifySignal : public MblMwDataSignal { + MblMwGpioPinNotifySignal(ResponseHeader header, MblMwMetaWearBoard* owner); + MblMwGpioPinNotifySignal(uint8_t** state_stream, MblMwMetaWearBoard *owner); + + virtual void unsubscribe(); +}; + +struct MblMwGpioAnalogSignal : public MblMwDataSignal { + MblMwGpioAnalogSignal(ResponseHeader header, MblMwMetaWearBoard* owner); + MblMwGpioAnalogSignal(uint8_t** state_stream, MblMwMetaWearBoard *owner); + + virtual void read() const; + virtual void read(const void* parameters) const; +}; + +void init_gpio_module(MblMwMetaWearBoard *board); +void create_gpio_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio_register.h new file mode 100644 index 0000000..2612384 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio_register.h @@ -0,0 +1,17 @@ +#pragma once + +#include "metawear/core/cpp/register.h" + +enum class GpioRegister : uint8_t { + SET_DO = 1, + CLEAR_DO, + PULL_UP_DI, + PULL_DOWN_DI, + NO_PULL_DI, + READ_AI_ABS_REF, + READ_AI_ADC, + READ_DI, + PIN_CHANGE, + PIN_CHANGE_NOTIFY, + PIN_CHANGE_NOTIFY_ENABLE +}; \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch.cpp new file mode 100644 index 0000000..faab124 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch.cpp @@ -0,0 +1,311 @@ +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include "metawear/sensor/gyro_bosch.h" +#include "gyro_bosch_private.h" +#include "gyro_bosch_register.h" +#include "utils.h" + +#include +#include +#include + +using std::forward_as_tuple; +using std::malloc; +using std::memcpy; +using std::memset; +using std::piecewise_construct; +using std::stringstream; +using std::unordered_map; +using std::vector; + +#define CREATE_BMI160_ROT_SIGNAL_SINGLE(offset) CREATE_BMI160_ROT_SIGNAL(DataInterpreter::BOSCH_ROTATION_SINGLE_AXIS, 1, offset) +#define CREATE_BMI160_ROT_SIGNAL(interpreter, channels, offset) new MblMwDataSignal(GYRO_BMI160_ROT_RESPONSE_HEADER, board, interpreter, \ + FirmwareConverter::BOSCH_ROTATION, channels, 2, 1, offset) +#define CREATE_BMI270_ROT_SIGNAL_SINGLE(offset) CREATE_BMI270_ROT_SIGNAL(DataInterpreter::BOSCH_ROTATION_SINGLE_AXIS, 1, offset) +#define CREATE_BMI270_ROT_SIGNAL(interpreter, channels, offset) new MblMwDataSignal(GYRO_BMI270_ROT_RESPONSE_HEADER, board, interpreter, \ + FirmwareConverter::BOSCH_ROTATION, channels, 2, 1, offset) + +const uint8_t MBL_MW_MODULE_GYRO_TYPE_BMI160 = 0; ///< Constant identifying the BMI160 accelerometer module type +const uint8_t MBL_MW_MODULE_GYRO_TYPE_BMI270 = 1; ///< Constant identifying the BMI270 accelerometer module type + +const float FSR_SCALE[5]= {16.4f, 32.8f, 65.6f, 131.2f, 262.4f}; +const uint8_t PACKED_ROT_REVISION= 1; +const ResponseHeader GYRO_BMI160_ROT_RESPONSE_HEADER(MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi160Register::DATA)), + GYRO_BMI160_PACKED_ROT_RESPONSE_HEADER(MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi160Register::PACKED_GYRO_DATA)), + GYRO_BMI270_ROT_RESPONSE_HEADER(MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi270Register::DATA)), + GYRO_BMI270_PACKED_ROT_RESPONSE_HEADER(MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi270Register::PACKED_GYRO_DATA)); + +struct GyroBoschConfig { + uint8_t gyr_odr : 4; + uint8_t gyr_bwp : 2; + uint8_t:2; + uint8_t gyr_range : 3; + uint8_t:5; +}; + +struct GyroBoschState { + MblMwFnBoardPtrInt read_config_completed; + void *read_config_context; +}; + +static unordered_map states; + +static int32_t received_config_response(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + memcpy(board->module_config.at(MBL_MW_MODULE_GYRO), response + 2, sizeof(GyroBoschConfig)); + + auto callback = states[board].read_config_completed; + auto context = states[board].read_config_context; + states[board].read_config_completed = nullptr; + states[board].read_config_context = nullptr; + callback(context, board, MBL_MW_STATUS_OK); + + return MBL_MW_STATUS_OK; +} + +float bosch_gyro_get_data_scale(const MblMwMetaWearBoard *board) { + return FSR_SCALE[((GyroBoschConfig*) board->module_config.at(MBL_MW_MODULE_GYRO))->gyr_range]; +} + +void init_gyro_module(MblMwMetaWearBoard *board) { + switch(board->module_info.at(MBL_MW_MODULE_GYRO).implementation) { + case MBL_MW_MODULE_GYRO_TYPE_BMI160: + if (board->module_info.count(MBL_MW_MODULE_GYRO) && board->module_info.at(MBL_MW_MODULE_GYRO).present) { + if (!board->module_config.count(MBL_MW_MODULE_GYRO)) { + GyroBoschConfig *new_config = (GyroBoschConfig*)malloc(sizeof(GyroBoschConfig)); + + memset(new_config, 0, sizeof(GyroBoschConfig)); + new_config->gyr_bwp = 2; + new_config->gyr_odr = MBL_MW_GYRO_BOSCH_ODR_100Hz; + new_config->gyr_range = MBL_MW_GYRO_BOSCH_RANGE_2000dps; + board->module_config.emplace(MBL_MW_MODULE_GYRO, new_config); + } + + MblMwDataSignal* rotation; + if (board->module_events.count(GYRO_BMI160_ROT_RESPONSE_HEADER)) { + rotation = dynamic_cast(board->module_events[GYRO_BMI160_ROT_RESPONSE_HEADER]); + } else { + rotation = CREATE_BMI160_ROT_SIGNAL(DataInterpreter::BOSCH_ROTATION, 3, 0); + board->module_events[GYRO_BMI160_ROT_RESPONSE_HEADER] = rotation; + } + if (!rotation->components.size()) { + rotation->components.push_back(CREATE_BMI160_ROT_SIGNAL_SINGLE(0)); + rotation->components.push_back(CREATE_BMI160_ROT_SIGNAL_SINGLE(2)); + rotation->components.push_back(CREATE_BMI160_ROT_SIGNAL_SINGLE(4)); + } + + board->responses[GYRO_BMI160_ROT_RESPONSE_HEADER]= response_handler_data_no_id; + + if (board->module_info.at(MBL_MW_MODULE_GYRO).revision >= PACKED_ROT_REVISION) { + if (!board->module_events.count(GYRO_BMI160_PACKED_ROT_RESPONSE_HEADER)) { + board->module_events[GYRO_BMI160_PACKED_ROT_RESPONSE_HEADER]= new MblMwDataSignal(GYRO_BMI160_PACKED_ROT_RESPONSE_HEADER, board, + DataInterpreter::BOSCH_ROTATION, FirmwareConverter::BOSCH_ROTATION, 3, 2, 1, 0); + } + board->responses[GYRO_BMI160_PACKED_ROT_RESPONSE_HEADER]= response_handler_packed_data; + } + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_GYRO, READ_REGISTER(ORDINAL(GyroBmi160Register::CONFIG))), + forward_as_tuple(received_config_response)); + + GyroBoschState newState = {nullptr}; + states.insert({board, newState}); + } + break; + case MBL_MW_MODULE_GYRO_TYPE_BMI270: + if (board->module_info.count(MBL_MW_MODULE_GYRO) && board->module_info.at(MBL_MW_MODULE_GYRO).present) { + if (!board->module_config.count(MBL_MW_MODULE_GYRO)) { + GyroBoschConfig *new_config = (GyroBoschConfig*)malloc(sizeof(GyroBoschConfig)); + + memset(new_config, 0, sizeof(GyroBoschConfig)); + new_config->gyr_bwp = 2; + new_config->gyr_odr = MBL_MW_GYRO_BOSCH_ODR_100Hz; + new_config->gyr_range = MBL_MW_GYRO_BOSCH_RANGE_2000dps; + board->module_config.emplace(MBL_MW_MODULE_GYRO, new_config); + } + + MblMwDataSignal* rotation; + if (board->module_events.count(GYRO_BMI270_ROT_RESPONSE_HEADER)) { + rotation = dynamic_cast(board->module_events[GYRO_BMI270_ROT_RESPONSE_HEADER]); + } else { + rotation = CREATE_BMI270_ROT_SIGNAL(DataInterpreter::BOSCH_ROTATION, 3, 0); + board->module_events[GYRO_BMI270_ROT_RESPONSE_HEADER] = rotation; + } + if (!rotation->components.size()) { + rotation->components.push_back(CREATE_BMI270_ROT_SIGNAL_SINGLE(0)); + rotation->components.push_back(CREATE_BMI270_ROT_SIGNAL_SINGLE(2)); + rotation->components.push_back(CREATE_BMI270_ROT_SIGNAL_SINGLE(4)); + } + + board->responses[GYRO_BMI270_ROT_RESPONSE_HEADER]= response_handler_data_no_id; + + if (!board->module_events.count(GYRO_BMI270_PACKED_ROT_RESPONSE_HEADER)) { + board->module_events[GYRO_BMI270_PACKED_ROT_RESPONSE_HEADER]= new MblMwDataSignal(GYRO_BMI270_PACKED_ROT_RESPONSE_HEADER, board, + DataInterpreter::BOSCH_ROTATION, FirmwareConverter::BOSCH_ROTATION, 3, 2, 1, 0); + } + board->responses[GYRO_BMI270_PACKED_ROT_RESPONSE_HEADER]= response_handler_packed_data; + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_GYRO, READ_REGISTER(ORDINAL(GyroBmi270Register::CONFIG))), + forward_as_tuple(received_config_response)); + + GyroBoschState newState = {nullptr}; + states.insert({board, newState}); + } + break; + default: + return; + } +} + +void free_gyro_module(MblMwMetaWearBoard *board) { + states.erase(board); +} + +MblMwDataSignal* mbl_mw_gyro_bmi160_get_rotation_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(GYRO_BMI160_ROT_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_gyro_bmi270_get_rotation_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(GYRO_BMI270_ROT_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_gyro_bmi160_get_high_freq_rotation_data_signal(const MblMwMetaWearBoard *board) { + return mbl_mw_gyro_bmi160_get_packed_rotation_data_signal(board); +} + +MblMwDataSignal* mbl_mw_gyro_bmi160_get_packed_rotation_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(GYRO_BMI160_PACKED_ROT_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_gyro_bmi270_get_packed_rotation_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(GYRO_BMI270_PACKED_ROT_RESPONSE_HEADER); +} + +void serialize_gyro_config(const MblMwMetaWearBoard *board, vector& state) { + SERIALIZE_MODULE_CONFIG(GyroBoschConfig, MBL_MW_MODULE_GYRO); +} + +void deserialize_gyro_config(MblMwMetaWearBoard *board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(GyroBoschConfig, MBL_MW_MODULE_GYRO); +} + +void mbl_mw_gyro_bmi160_set_odr(MblMwMetaWearBoard *board, MblMwGyroBoschOdr odr) { + ((GyroBoschConfig*) board->module_config.at(MBL_MW_MODULE_GYRO))->gyr_odr= odr; +} + +void mbl_mw_gyro_bmi160_set_range(MblMwMetaWearBoard *board, MblMwGyroBoschRange range) { + ((GyroBoschConfig*) board->module_config.at(MBL_MW_MODULE_GYRO))->gyr_range= range; +} + +void mbl_mw_gyro_bmi160_write_config(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi160Register::CONFIG)}; + memcpy(command + 2, board->module_config.at(MBL_MW_MODULE_GYRO), sizeof(GyroBoschConfig)); + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi270_set_odr(MblMwMetaWearBoard *board, MblMwGyroBoschOdr odr) { + ((GyroBoschConfig*) board->module_config.at(MBL_MW_MODULE_GYRO))->gyr_odr= odr; +} + +void mbl_mw_gyro_bmi270_set_range(MblMwMetaWearBoard *board, MblMwGyroBoschRange range) { + ((GyroBoschConfig*) board->module_config.at(MBL_MW_MODULE_GYRO))->gyr_range= range; +} + +void mbl_mw_gyro_bmi270_write_config(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi270Register::CONFIG)}; + memcpy(command + 2, board->module_config.at(MBL_MW_MODULE_GYRO), sizeof(GyroBoschConfig)); + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi160_read_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed) { + states[board].read_config_context = context; + states[board].read_config_completed = completed; + + uint8_t command[2]= {MBL_MW_MODULE_GYRO, READ_REGISTER(ORDINAL(GyroBmi160Register::CONFIG))}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi270_read_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed) { + states[board].read_config_context = context; + states[board].read_config_completed = completed; + + uint8_t command[2]= {MBL_MW_MODULE_GYRO, READ_REGISTER(ORDINAL(GyroBmi270Register::CONFIG))}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi160_start(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi160Register::POWER_MODE), 1}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi160_stop(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi160Register::POWER_MODE), 0}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi270_start(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi270Register::POWER_MODE), 1}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi270_stop(const MblMwMetaWearBoard *board) { + uint8_t command[3]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi270Register::POWER_MODE), 0}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi160_enable_rotation_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi160Register::DATA_INTERRUPT_ENABLE), 0x1, 0x0}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi160_disable_rotation_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi160Register::DATA_INTERRUPT_ENABLE), 0x0, 0x1}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi270_enable_rotation_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi270Register::DATA_INTERRUPT_ENABLE), 0x1, 0x0}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi270_disable_rotation_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[4]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi270Register::DATA_INTERRUPT_ENABLE), 0x0, 0x1}; + SEND_COMMAND; +} + +void mbl_mw_gyro_bmi270_acc_offsets(const MblMwMetaWearBoard* board, uint8_t x_offset, uint8_t y_offset, uint8_t z_offset) { + uint8_t gyr_usr_off_x_7_0 = x_offset; + uint8_t gyr_usr_off_y_7_0 = y_offset; + uint8_t gyr_usr_off_z_7_0 = z_offset; + + uint8_t command[5]= {MBL_MW_MODULE_GYRO, ORDINAL(GyroBmi270Register::OFFSET), gyr_usr_off_x_7_0, gyr_usr_off_y_7_0, gyr_usr_off_z_7_0}; + SEND_COMMAND; +} + +void create_gyro_uri(const MblMwDataSignal* signal, std::stringstream& uri) { + switch(signal->owner->module_info.at(MBL_MW_MODULE_GYRO).implementation) { + case MBL_MW_MODULE_GYRO_TYPE_BMI160: + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(GyroBmi160Register::DATA): + uri << "angular-velocity"; + if (signal->length() <= 2) { + uri << "[" << (int) (signal->offset >> 1) << "]"; + } + } + break; + case MBL_MW_MODULE_GYRO_TYPE_BMI270: + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(GyroBmi270Register::DATA): + uri << "angular-velocity"; + if (signal->length() <= 2) { + uri << "[" << (int) (signal->offset >> 1) << "]"; + } + } + break; + + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch_private.h new file mode 100644 index 0000000..74835e7 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch_private.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +float bosch_gyro_get_data_scale(const MblMwMetaWearBoard *board); + +void init_gyro_module(MblMwMetaWearBoard *board); +void free_gyro_module(MblMwMetaWearBoard *board); +void serialize_gyro_config(const MblMwMetaWearBoard *board, std::vector& state); +void deserialize_gyro_config(MblMwMetaWearBoard *board, uint8_t** state_stream); +void create_gyro_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch_register.h new file mode 100644 index 0000000..efadb7e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch_register.h @@ -0,0 +1,18 @@ +#pragma once + +enum class GyroBmi160Register : uint8_t { + POWER_MODE = 1, + DATA_INTERRUPT_ENABLE, + CONFIG, + DATA = 5, + PACKED_GYRO_DATA = 0x7 +}; + +enum class GyroBmi270Register : uint8_t { + POWER_MODE = 1, + DATA_INTERRUPT_ENABLE, + CONFIG, + DATA = 4, + PACKED_GYRO_DATA = 0x5, + OFFSET +}; \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280.cpp new file mode 100644 index 0000000..968db2e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280.cpp @@ -0,0 +1,45 @@ +#include "metawear/sensor/humidity_bme280.h" +#include "humidity_bme280_private.h" +#include "humidity_bme280_register.h" +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include +#include + +using std::stringstream; + +const ResponseHeader HUMIDITY_BME280_ADC_RESPONSE_HEADER(MBL_MW_MODULE_HUMIDITY, READ_REGISTER(ORDINAL(HumidityBme280Register::HUMIDITY))); + +void init_humidity_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_HUMIDITY) && board->module_info.at(MBL_MW_MODULE_HUMIDITY).present) { + if (!board->module_events.count(HUMIDITY_BME280_ADC_RESPONSE_HEADER)) { + board->module_events[HUMIDITY_BME280_ADC_RESPONSE_HEADER] = new MblMwDataSignal(HUMIDITY_BME280_ADC_RESPONSE_HEADER, board, + DataInterpreter::BME280_HUMIDITY, FirmwareConverter::BME280_HUMIDITY, 1, 4, 0, 0); + } + board->responses[HUMIDITY_BME280_ADC_RESPONSE_HEADER]= response_handler_data_no_id; + } +} + +MblMwDataSignal* mbl_mw_humidity_bme280_get_percentage_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(HUMIDITY_BME280_ADC_RESPONSE_HEADER); +} + +void mbl_mw_humidity_bme280_set_oversampling(const MblMwMetaWearBoard *board, MblMwHumidityBme280Oversampling oversampling) { + uint8_t command[3]= { MBL_MW_MODULE_HUMIDITY, ORDINAL(HumidityBme280Register::MODE), static_cast(oversampling) }; + SEND_COMMAND; +} + +void create_humidity_uri(const MblMwDataSignal* signal, std::stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(HumidityBme280Register::HUMIDITY): + uri << "relative-humidity"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280_private.h new file mode 100644 index 0000000..b70c5f4 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280_private.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include "metawear/core/metawearboard_fwd.h" + +void init_humidity_module(MblMwMetaWearBoard *board); +void create_humidity_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280_register.h new file mode 100644 index 0000000..e23cefc --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280_register.h @@ -0,0 +1,6 @@ +#pragma once + +enum class HumidityBme280Register : uint8_t { + HUMIDITY= 1, + MODE +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150.cpp new file mode 100644 index 0000000..2967cea --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150.cpp @@ -0,0 +1,122 @@ +#include "metawear/sensor/magnetometer_bmm150.h" +#include "magnetometer_bmm150_register.h" +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +using std::stringstream; + +#define CREATE_BFIELD_SIGNAL_SINGLE(offset) CREATE_BFIELD_SIGNAL(DataInterpreter::BMM150_B_FIELD_SINGLE_AXIS, 1, offset) +#define CREATE_BFIELD_SIGNAL(interpreter, channels, offset) new MblMwDataSignal(BMM150_MAG_DATA_RESPONSE_HEADER, board, interpreter, \ + FirmwareConverter::BOSCH_MAGNETOMETER, channels, 2, 1, offset) + +const uint8_t PACKED_MAG_REVISION = 1, SUSPEND_REVISION = 2; +const ResponseHeader BMM150_MAG_DATA_RESPONSE_HEADER(MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::MAG_DATA)), + BMM150_MAG_PACKED_DATA_RESPONSE_HEADER(MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::PACKED_MAG_DATA));; + +void init_magnetometer_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_MAGNETOMETER) && board->module_info.at(MBL_MW_MODULE_MAGNETOMETER).present) { + MblMwDataSignal* bfield; + if (board->module_events.count(BMM150_MAG_DATA_RESPONSE_HEADER)) { + bfield = dynamic_cast(board->module_events[BMM150_MAG_DATA_RESPONSE_HEADER]); + } else { + bfield = CREATE_BFIELD_SIGNAL(DataInterpreter::BMM150_B_FIELD, 3, 0); + board->module_events[BMM150_MAG_DATA_RESPONSE_HEADER] = bfield; + } + if (!bfield->components.size()) { + bfield->components.push_back(CREATE_BFIELD_SIGNAL_SINGLE(0)); + bfield->components.push_back(CREATE_BFIELD_SIGNAL_SINGLE(2)); + bfield->components.push_back(CREATE_BFIELD_SIGNAL_SINGLE(4)); + } + + board->responses[BMM150_MAG_DATA_RESPONSE_HEADER] = response_handler_data_no_id; + + if (board->module_info.at(MBL_MW_MODULE_MAGNETOMETER).revision >= PACKED_MAG_REVISION) { + if (!board->module_events.count(BMM150_MAG_PACKED_DATA_RESPONSE_HEADER)) { + board->module_events[BMM150_MAG_PACKED_DATA_RESPONSE_HEADER]= new MblMwDataSignal(BMM150_MAG_PACKED_DATA_RESPONSE_HEADER, board, + DataInterpreter::BMM150_B_FIELD, FirmwareConverter::BOSCH_MAGNETOMETER, 3, 2, 1, 0); + } + board->responses[BMM150_MAG_PACKED_DATA_RESPONSE_HEADER]= response_handler_packed_data; + } + } +} + +MblMwDataSignal* mbl_mw_mag_bmm150_get_b_field_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(BMM150_MAG_DATA_RESPONSE_HEADER); +} + +MblMwDataSignal* mbl_mw_mag_bmm150_get_packed_b_field_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(BMM150_MAG_PACKED_DATA_RESPONSE_HEADER); +} + +void mbl_mw_mag_bmm150_configure(const MblMwMetaWearBoard *board, uint16_t xy_reps, uint16_t z_reps, MblMwMagBmm150Odr odr) { + if (board->module_info.at(MBL_MW_MODULE_MAGNETOMETER).revision >= SUSPEND_REVISION) { + mbl_mw_mag_bmm150_stop(board); + } + + uint8_t data_rep_cmd[4]= { MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::DATA_REPETITIONS), + static_cast((xy_reps - 1) / 2), static_cast(z_reps - 1) }; + send_command(board, data_rep_cmd, sizeof(data_rep_cmd)); + + uint8_t data_rate_cmd[3]= { MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::DATA_RATE), static_cast(odr) }; + send_command(board, data_rate_cmd, sizeof(data_rate_cmd)); +} + +void mbl_mw_mag_bmm150_set_preset(const MblMwMetaWearBoard *board, MblMwMagBmm150Preset preset) { + switch (preset) { + case MBL_MW_MAG_BMM150_PRESET_LOW_POWER: + mbl_mw_mag_bmm150_configure(board, 3, 3, MBL_MW_MAG_BMM150_ODR_10Hz); + break; + case MBL_MW_MAG_BMM150_PRESET_REGULAR: + mbl_mw_mag_bmm150_configure(board, 9, 15, MBL_MW_MAG_BMM150_ODR_10Hz); + break; + case MBL_MW_MAG_BMM150_PRESET_ENHANCED_REGULAR: + mbl_mw_mag_bmm150_configure(board, 15, 27, MBL_MW_MAG_BMM150_ODR_10Hz); + break; + case MBL_MW_MAG_BMM150_PRESET_HIGH_ACCURACY: + mbl_mw_mag_bmm150_configure(board, 47, 83, MBL_MW_MAG_BMM150_ODR_20Hz); + break; + } +} + +void mbl_mw_mag_bmm150_enable_b_field_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[4]= { MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::DATA_INTERRUPT_ENABLE), 1, 0 }; + SEND_COMMAND; +} + +void mbl_mw_mag_bmm150_disable_b_field_sampling(const MblMwMetaWearBoard *board) { + uint8_t command[4]= { MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::DATA_INTERRUPT_ENABLE), 0, 1 }; + SEND_COMMAND; +} + +void mbl_mw_mag_bmm150_start(const MblMwMetaWearBoard *board) { + uint8_t command[3]= { MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::POWER_MODE), 1 }; + SEND_COMMAND; +} + +void mbl_mw_mag_bmm150_stop(const MblMwMetaWearBoard *board) { + uint8_t command[3]= { MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::POWER_MODE), 0 }; + SEND_COMMAND; +} + +void mbl_mw_mag_bmm150_suspend(const MblMwMetaWearBoard *board) { + if (board->module_info.at(MBL_MW_MODULE_MAGNETOMETER).revision >= SUSPEND_REVISION) { + uint8_t command[3]= { MBL_MW_MODULE_MAGNETOMETER, ORDINAL(MagnetometerBmm150Register::POWER_MODE), 2 }; + SEND_COMMAND; + } +} + +void create_magnetometer_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(MagnetometerBmm150Register::MAG_DATA): + uri << "magnetic-field"; + if (signal->length() <= 2) { + uri << "[" << (int) (signal->offset >> 1) << "]"; + } + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150_private.h new file mode 100644 index 0000000..da14081 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150_private.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "metawear/core/metawearboard_fwd.h" + +void init_magnetometer_module(MblMwMetaWearBoard *board); +void free_magnetometer_module(MblMwMetaWearBoard *board); +void create_magnetometer_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150_register.h new file mode 100644 index 0000000..e2eb413 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150_register.h @@ -0,0 +1,10 @@ +#pragma once + +enum class MagnetometerBmm150Register : uint8_t { + POWER_MODE = 1, + DATA_INTERRUPT_ENABLE, + DATA_RATE, + DATA_REPETITIONS, + MAG_DATA, + PACKED_MAG_DATA= 0x09 +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature.cpp new file mode 100644 index 0000000..33d8533 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature.cpp @@ -0,0 +1,65 @@ +#include + +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/register.h" + +#include "metawear/sensor/multichanneltemperature.h" +#include "multichanneltemperature_private.h" +#include "multichanneltemperature_register.h" + +using std::forward_as_tuple; +using std::out_of_range; +using std::piecewise_construct; +using std::stringstream; + +void init_multichannel_temp_module(MblMwMetaWearBoard *board) { + for(uint8_t channel = 0; channel < (uint8_t) board->module_info.at(MBL_MW_MODULE_TEMPERATURE).extra.size(); channel++) { + ResponseHeader header(MBL_MW_MODULE_TEMPERATURE, READ_REGISTER(ORDINAL(MultiChannelTempRegister::TEMPERATURE)), channel); + if (!board->module_events.count(header)) { + board->module_events[header] = new MblMwDataSignal(header, board, DataInterpreter::TEMPERATURE, + FirmwareConverter::TEMPERATURE, 1, 2, 1, 0); + } + } + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_TEMPERATURE, READ_REGISTER(ORDINAL(MultiChannelTempRegister::TEMPERATURE))), + forward_as_tuple(response_handler_data_with_id)); +} + +MblMwDataSignal* mbl_mw_multi_chnl_temp_get_temperature_data_signal(const MblMwMetaWearBoard *board, uint8_t channel) { + ResponseHeader header(MBL_MW_MODULE_TEMPERATURE, READ_REGISTER(ORDINAL(MultiChannelTempRegister::TEMPERATURE)), channel); + return board->module_events.count(header) ? dynamic_cast(board->module_events.at(header)) : nullptr; +} + +void mbl_mw_multi_chnl_temp_configure_ext_thermistor(const MblMwMetaWearBoard *board, uint8_t channel, uint8_t data_pin, + uint8_t pulldown_pin, uint8_t active_high) { + uint8_t command[6]= {MBL_MW_MODULE_TEMPERATURE, ORDINAL(MultiChannelTempRegister::MODE), channel, data_pin, pulldown_pin, active_high}; + SEND_COMMAND; +} + +MblMwTemperatureSource mbl_mw_multi_chnl_temp_get_source(const MblMwMetaWearBoard *board, uint8_t channel) { + try { + return (MblMwTemperatureSource) board->module_info.at(MBL_MW_MODULE_TEMPERATURE).extra.at(channel); + } catch (const out_of_range&) { + return MBL_MW_TEMPERATURE_SOURCE_INVALID; + } +} + +uint8_t mbl_mw_multi_chnl_temp_get_num_channels(const MblMwMetaWearBoard *board) { + try { + return (uint8_t) board->module_info.at(MBL_MW_MODULE_TEMPERATURE).extra.size(); + } catch (const out_of_range&) { + return 0; + } +} + +void create_temp_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(MultiChannelTempRegister::TEMPERATURE): + uri << "temperature[" << (int) signal->header.data_id << "]"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature_private.h new file mode 100644 index 0000000..cdea82a --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature_private.h @@ -0,0 +1,8 @@ +#pragma once + +#include "metawear/core/metawearboard_fwd.h" + +#include + +void init_multichannel_temp_module(MblMwMetaWearBoard *board); +void create_temp_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature_register.h new file mode 100644 index 0000000..9d0d418 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature_register.h @@ -0,0 +1,6 @@ +#pragma once + +enum class MultiChannelTempRegister : uint8_t { + TEMPERATURE = 1, + MODE +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671.cpp new file mode 100644 index 0000000..8adb83f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671.cpp @@ -0,0 +1,90 @@ +#include "metawear/sensor/proximity_tsl2671.h" +#include "proximity_tsl2671_private.h" +#include "proximity_tsl2671_register.h" +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include +#include +#include + +using std::calloc; +using std::stringstream; + +const ResponseHeader PROXIMITY_TSL2671_ADC_RESPONSE_HEADER(MBL_MW_MODULE_PROXIMITY, READ_REGISTER(ORDINAL(ProximityTsl2671Register::PROXIMITY))); + +struct Tsl2671Config { + uint8_t integration_time; + uint8_t n_pulses; + uint8_t :4; + uint8_t receiver_channel:2; + uint8_t transmitter_current:2; +}; + +void init_proximity_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_PROXIMITY) && board->module_info.at(MBL_MW_MODULE_PROXIMITY).present) { + if (!board->module_config.count(MBL_MW_MODULE_PROXIMITY)) { + Tsl2671Config* new_config = (Tsl2671Config*)calloc(1, sizeof(Tsl2671Config)); + new_config->integration_time = 0xff; + new_config->n_pulses = 1; + new_config->receiver_channel = MBL_MW_PROXIMITY_TSL2671_CHANNEL_1; + new_config->transmitter_current = MBL_MW_PROXIMITY_TSL2671_CURRENT_25mA; + board->module_config.emplace(MBL_MW_MODULE_PROXIMITY, new_config); + } + + if (!board->module_events.count(PROXIMITY_TSL2671_ADC_RESPONSE_HEADER)) { + board->module_events[PROXIMITY_TSL2671_ADC_RESPONSE_HEADER] = new MblMwDataSignal(PROXIMITY_TSL2671_ADC_RESPONSE_HEADER, board, + DataInterpreter::UINT32, 1, 2, 0, 0); + } + board->responses[PROXIMITY_TSL2671_ADC_RESPONSE_HEADER]= response_handler_data_no_id; + } +} + +void serialize_proximity_config(const MblMwMetaWearBoard *board, std::vector& state) { + SERIALIZE_MODULE_CONFIG(Tsl2671Config, MBL_MW_MODULE_PROXIMITY); +} + +void deserialize_proximity_config(MblMwMetaWearBoard *board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(Tsl2671Config, MBL_MW_MODULE_PROXIMITY); +} + +MblMwDataSignal* mbl_mw_proximity_tsl2671_get_adc_data_signal(const MblMwMetaWearBoard *board) { + GET_DATA_SIGNAL(PROXIMITY_TSL2671_ADC_RESPONSE_HEADER); +} + +void mbl_mw_proximity_tsl2671_set_integration_time(MblMwMetaWearBoard *board, float time) { + ((Tsl2671Config*) board->module_config.at(MBL_MW_MODULE_PROXIMITY))->integration_time= (uint8_t) (256.f - time / 2.72f); +} + +void mbl_mw_proximity_tsl2671_set_n_pulses(MblMwMetaWearBoard *board, uint8_t n_pulses) { + ((Tsl2671Config*) board->module_config.at(MBL_MW_MODULE_PROXIMITY))->n_pulses= n_pulses; +} + +void mbl_mw_proximity_tsl2671_set_receiver_channel(MblMwMetaWearBoard *board, MblMwProximityTsl2671Channel channel) { + ((Tsl2671Config*) board->module_config.at(MBL_MW_MODULE_PROXIMITY))->receiver_channel= channel; +} + +void mbl_mw_proximity_tsl2671_set_transmitter_current(MblMwMetaWearBoard *board, MblMwProximityTsl2671Current current) { + ((Tsl2671Config*) board->module_config.at(MBL_MW_MODULE_PROXIMITY))->transmitter_current= current; +} + +void mbl_mw_proximity_tsl2671_write_config(const MblMwMetaWearBoard *board) { + uint8_t command[5]= { MBL_MW_MODULE_PROXIMITY, ORDINAL(ProximityTsl2671Register::MODE) }; + memcpy(command + 2, board->module_config.at(MBL_MW_MODULE_PROXIMITY), sizeof(Tsl2671Config)); + + SEND_COMMAND; +} + +void create_proximity_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(ProximityTsl2671Register::PROXIMITY): + uri << "proximity"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671_private.h new file mode 100644 index 0000000..7ced4b5 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671_private.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +void init_proximity_module(MblMwMetaWearBoard *board); +void serialize_proximity_config(const MblMwMetaWearBoard *board, std::vector& state); +void deserialize_proximity_config(MblMwMetaWearBoard *board, uint8_t** state_stream); +void create_proximity_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671_register.h new file mode 100644 index 0000000..a72067c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671_register.h @@ -0,0 +1,6 @@ +#pragma once + +enum class ProximityTsl2671Register : uint8_t { + PROXIMITY= 1, + MODE +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion.cpp new file mode 100644 index 0000000..9c42a25 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion.cpp @@ -0,0 +1,420 @@ +#include "metawear/core/module.h" +#include "metawear/core/status.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/metawearboard_macro.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +#include "metawear/sensor/accelerometer.h" +#include "metawear/sensor/gyro_bosch.h" +#include "metawear/sensor/magnetometer_bmm150.h" +#include "metawear/sensor/sensor_fusion.h" +#include "sensor_fusion_private.h" +#include "sensor_fusion_register.h" +#include "utils.h" + +#include +#include +#include + +using std::forward_as_tuple; +using std::malloc; +using std::memset; +using std::piecewise_construct; +using std::stringstream; +using std::strlen; +using std::unordered_map; + +#define CORRECTED_ACC_RESPONSE_HEADER RESPONSE_HEADERS[MBL_MW_SENSOR_FUSION_DATA_CORRECTED_ACC] +#define CORRECTED_GYRO_RESPONSE_HEADER RESPONSE_HEADERS[MBL_MW_SENSOR_FUSION_DATA_CORRECTED_GYRO] +#define CORRECTED_MAG_RESPONSE_HEADER RESPONSE_HEADERS[MBL_MW_SENSOR_FUSION_DATA_CORRECTED_MAG] +#define QUATERNION_RESPONSE_HEADER RESPONSE_HEADERS[MBL_MW_SENSOR_FUSION_DATA_QUATERNION] +#define EULER_ANGLES_RESPONSE_HEADER RESPONSE_HEADERS[MBL_MW_SENSOR_FUSION_DATA_EULER_ANGLE] +#define GRAVITY_VECTOR_RESPONSE_HEADER RESPONSE_HEADERS[MBL_MW_SENSOR_FUSION_DATA_GRAVITY_VECTOR] +#define LINEAR_ACC_RESPONSE_HEADER RESPONSE_HEADERS[MBL_MW_SENSOR_FUSION_DATA_LINEAR_ACC] + +const float ACC_RANGES[] = {2.f, 4.f, 8.f, 16.f}; + +const ResponseHeader RESPONSE_HEADERS[] { + ResponseHeader(MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::CORRECTED_ACC)), + ResponseHeader(MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::CORRECTED_GYRO)), + ResponseHeader(MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::CORRECTED_MAG)), + ResponseHeader(MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::QUATERNION)), + ResponseHeader(MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::EULER_ANGLES)), + ResponseHeader(MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::GRAVITY_VECTOR)), + ResponseHeader(MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::LINEAR_ACC)) +}; + +const ResponseHeader CALIB_STATE_RESPONSE_HEADER(MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::CALIBRATION_STATE))); +const uint8_t CALIBRATION_REVISION = 1, CALIB_DATA_REVISION = 2, RESET_ORIENTATION_REVISION = 3; + +struct SensorFusionState { + struct { + uint8_t mode; + uint8_t acc_range:4; + uint8_t gyro_range:4; + } config; + uint8_t enable_mask; +}; + +struct SensorFusionTransientState { + MblMwCalibrationData* calib_data; + MblMwFnBoardPtrInt read_config_completed; + MblMwFnBoardPtrCalibDataPtr read_calib_data_completed; + void *read_config_context, *read_calib_data_context; +}; + +static unordered_map transient_states; + +static int32_t received_config_response(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + auto state = (SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION); + memcpy(&(state->config), response + 2, sizeof(state->config)); + + auto callback = transient_states[board].read_config_completed; + auto context = transient_states[board].read_config_context; + transient_states[board].read_config_completed = nullptr; + transient_states[board].read_config_context = nullptr; + callback(context, board, MBL_MW_STATUS_OK); + + return 0; +} + +static int32_t received_acc_cal_data(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + MblMwCalibrationData* data = (MblMwCalibrationData*) malloc(sizeof(MblMwCalibrationData)); + memcpy(data->acc, response + 2, 10); + transient_states[board].calib_data = data; + + uint8_t command[2] = { MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::GYRO_CAL_DATA)) }; + SEND_COMMAND; + + return 0; +} + +static int32_t received_gyro_cal_data(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + memcpy(transient_states[board].calib_data->gyro, response + 2, 10); + + uint8_t command[2] = { MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::MAG_CAL_DATA)) }; + SEND_COMMAND; + + return 0; +} + +static int32_t received_mag_cal_data(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) { + memcpy(transient_states[board].calib_data->mag, response + 2, 10); + + transient_states[board].read_calib_data_completed(transient_states[board].read_calib_data_context, board, transient_states[board].calib_data); + + return 0; +} + +void init_sensor_fusion_module(MblMwMetaWearBoard* board) { + if (board->module_info.count(MBL_MW_MODULE_SENSOR_FUSION) && board->module_info.at(MBL_MW_MODULE_SENSOR_FUSION).present) { + if (!board->module_config.count(MBL_MW_MODULE_SENSOR_FUSION)) { + SensorFusionState* new_state = (SensorFusionState*) malloc(sizeof(SensorFusionState)); + new_state->config.mode = MBL_MW_SENSOR_FUSION_MODE_SLEEP; + new_state->config.acc_range = MBL_MW_SENSOR_FUSION_ACC_RANGE_16G; + // The +1 here is because the sensor fusion library defines a 2048 at + // location zero which our hardware doesn't acutally support, so we + // essentially shift the MBL_MW_SENSOR_FUSION_GYRO_RANGE enum by 1 + new_state->config.gyro_range = MBL_MW_SENSOR_FUSION_GYRO_RANGE_2000DPS + 1; + new_state->enable_mask = 0; + board->module_config.emplace(MBL_MW_MODULE_SENSOR_FUSION, new_state); + } + + for(auto& it: RESPONSE_HEADERS) { + board->responses[it] = response_handler_data_no_id; + } + + if (!board->module_events.count(CORRECTED_ACC_RESPONSE_HEADER)) { + board->module_events[CORRECTED_ACC_RESPONSE_HEADER] = new MblMwDataSignal(CORRECTED_ACC_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_FUSION_CORRECTED_ACC, FirmwareConverter::DEFAULT, 1, 13, 1, 0); + } + + if (!board->module_events.count(CORRECTED_GYRO_RESPONSE_HEADER)) { + board->module_events[CORRECTED_GYRO_RESPONSE_HEADER] = new MblMwDataSignal(CORRECTED_GYRO_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_FUSION_CORRECTED_FLOAT_VECTOR3, FirmwareConverter::DEFAULT, 1, 13, 1, 0); + } + + if (!board->module_events.count(CORRECTED_MAG_RESPONSE_HEADER)) { + board->module_events[CORRECTED_MAG_RESPONSE_HEADER] = new MblMwDataSignal(CORRECTED_MAG_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_FUSION_CORRECTED_FLOAT_VECTOR3, FirmwareConverter::DEFAULT, 1, 13, 1, 0); + } + + if (!board->module_events.count(QUATERNION_RESPONSE_HEADER)) { + board->module_events[QUATERNION_RESPONSE_HEADER] = new MblMwDataSignal(QUATERNION_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_FUSION_QUATERNION, FirmwareConverter::DEFAULT, 4, 4, 1, 0); + } + + if (!board->module_events.count(EULER_ANGLES_RESPONSE_HEADER)) { + board->module_events[EULER_ANGLES_RESPONSE_HEADER] = new MblMwDataSignal(EULER_ANGLES_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_FUSION_EULER_ANGLE, FirmwareConverter::DEFAULT, 4, 4, 1, 0); + } + + if (!board->module_events.count(GRAVITY_VECTOR_RESPONSE_HEADER)) { + board->module_events[GRAVITY_VECTOR_RESPONSE_HEADER] = new MblMwDataSignal(GRAVITY_VECTOR_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_FUSION_FLOAT_VECTOR3, FirmwareConverter::DEFAULT, 3, 4, 1, 0); + } + + if (!board->module_events.count(LINEAR_ACC_RESPONSE_HEADER)) { + board->module_events[LINEAR_ACC_RESPONSE_HEADER] = new MblMwDataSignal(LINEAR_ACC_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_FUSION_FLOAT_VECTOR3, FirmwareConverter::DEFAULT, 3, 4, 1, 0); + } + + if (!board->module_events.count(CALIB_STATE_RESPONSE_HEADER)) { + board->module_events[CALIB_STATE_RESPONSE_HEADER] = new MblMwDataSignal(CALIB_STATE_RESPONSE_HEADER, board, + DataInterpreter::SENSOR_FUSION_CALIB_STATE, FirmwareConverter::DEFAULT, 3, 1, 0, 0); + } + + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::MODE))), + forward_as_tuple(received_config_response)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::CALIBRATION_STATE))), + forward_as_tuple(response_handler_data_no_id)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::ACC_CAL_DATA))), + forward_as_tuple(received_acc_cal_data)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::GYRO_CAL_DATA))), + forward_as_tuple(received_gyro_cal_data)); + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::MAG_CAL_DATA))), + forward_as_tuple(received_mag_cal_data)); + + SensorFusionTransientState newState = {nullptr}; + transient_states.insert({board, newState}); + } +} + +void free_sensor_fusion_module(MblMwMetaWearBoard* board) { + transient_states.erase(board); +} + +void serialize_sensor_fusion_config(const MblMwMetaWearBoard *board, std::vector& state) { + SERIALIZE_MODULE_CONFIG(SensorFusionState, MBL_MW_MODULE_SENSOR_FUSION); +} + +void deserialize_sensor_fusion_config(MblMwMetaWearBoard *board, uint8_t** state_stream) { + DESERIALIZE_MODULE_CONFIG(SensorFusionState, MBL_MW_MODULE_SENSOR_FUSION); +} + +MblMwDataSignal* mbl_mw_sensor_fusion_get_data_signal(const MblMwMetaWearBoard* board, MblMwSensorFusionData data) { + GET_DATA_SIGNAL(RESPONSE_HEADERS[data]); +} + +MblMwDataSignal* mbl_mw_sensor_fusion_calibration_state_data_signal(const MblMwMetaWearBoard* board) { + if (board->module_info.at(MBL_MW_MODULE_SENSOR_FUSION).revision < CALIBRATION_REVISION) { + return nullptr; + } + GET_DATA_SIGNAL(CALIB_STATE_RESPONSE_HEADER); +} + +void mbl_mw_sensor_fusion_set_mode(MblMwMetaWearBoard* board, MblMwSensorFusionMode mode) { + ((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->config.mode = mode; +} + +void mbl_mw_sensor_fusion_set_acc_range(MblMwMetaWearBoard* board, MblMwSensorFusionAccRange range) { + ((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->config.acc_range = range; +} + +void mbl_mw_sensor_fusion_set_gyro_range(MblMwMetaWearBoard* board, MblMwSensorFusionGyroRange range) { + ((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->config.gyro_range = (range + 1); +} + +void mbl_mw_sensor_fusion_write_config(MblMwMetaWearBoard* board) { + auto state = (SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION); + + uint8_t command[4] = {MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::MODE)}; + memcpy(command + 2, &(state->config), sizeof(state->config)); + SEND_COMMAND; + + switch(state->config.mode) { + case MBL_MW_SENSOR_FUSION_MODE_SLEEP: + break; + case MBL_MW_SENSOR_FUSION_MODE_NDOF: + mbl_mw_acc_set_range(board, ACC_RANGES[state->config.acc_range]); + mbl_mw_acc_set_odr(board, 100.f); + mbl_mw_acc_write_acceleration_config(board); + + mbl_mw_gyro_bmi160_set_range(board, (MblMwGyroBoschRange) (state->config.gyro_range - 1)); + mbl_mw_gyro_bmi160_set_odr(board, MBL_MW_GYRO_BOSCH_ODR_100Hz); + mbl_mw_gyro_bmi160_write_config(board); + + mbl_mw_mag_bmm150_configure(board, 9, 15, MBL_MW_MAG_BMM150_ODR_25Hz); + break; + case MBL_MW_SENSOR_FUSION_MODE_IMU_PLUS: + mbl_mw_acc_set_range(board, ACC_RANGES[state->config.acc_range]); + mbl_mw_acc_set_odr(board, 100.f); + mbl_mw_acc_write_acceleration_config(board); + + mbl_mw_gyro_bmi160_set_range(board, (MblMwGyroBoschRange) (state->config.gyro_range - 1)); + mbl_mw_gyro_bmi160_set_odr(board, MBL_MW_GYRO_BOSCH_ODR_100Hz); + mbl_mw_gyro_bmi160_write_config(board); + break; + case MBL_MW_SENSOR_FUSION_MODE_COMPASS: + mbl_mw_acc_set_range(board, ACC_RANGES[state->config.acc_range]); + mbl_mw_acc_set_odr(board, 25.f); + mbl_mw_acc_write_acceleration_config(board); + + mbl_mw_mag_bmm150_configure(board, 9, 15, MBL_MW_MAG_BMM150_ODR_25Hz); + break; + case MBL_MW_SENSOR_FUSION_MODE_M4G: + mbl_mw_acc_set_range(board, ACC_RANGES[state->config.acc_range]); + mbl_mw_acc_set_odr(board, 50.f); + mbl_mw_acc_write_acceleration_config(board); + + mbl_mw_mag_bmm150_configure(board, 9, 15, MBL_MW_MAG_BMM150_ODR_25Hz); + } +} + +void mbl_mw_sensor_fusion_read_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed) { + transient_states[board].read_config_context = context; + transient_states[board].read_config_completed = completed; + uint8_t command[2] = { MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::MODE)) }; + SEND_COMMAND; +} + +void mbl_mw_sensor_fusion_enable_data(MblMwMetaWearBoard* board, MblMwSensorFusionData data) { + ((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->enable_mask |= (0x1 << (int) data); +} + +void mbl_mw_sensor_fusion_clear_enabled_mask(MblMwMetaWearBoard* board) { + ((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->enable_mask = 0x0; +} + +void mbl_mw_sensor_fusion_start(const MblMwMetaWearBoard* board) { + switch(((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->config.mode) { + case MBL_MW_SENSOR_FUSION_MODE_NDOF: + mbl_mw_acc_enable_acceleration_sampling(board); + mbl_mw_gyro_bmi160_enable_rotation_sampling(board); + mbl_mw_mag_bmm150_enable_b_field_sampling(board); + mbl_mw_acc_start(board); + mbl_mw_gyro_bmi160_start(board); + mbl_mw_mag_bmm150_start(board); + break; + case MBL_MW_SENSOR_FUSION_MODE_IMU_PLUS: + mbl_mw_acc_enable_acceleration_sampling(board); + mbl_mw_gyro_bmi160_enable_rotation_sampling(board); + mbl_mw_acc_start(board); + mbl_mw_gyro_bmi160_start(board); + break; + case MBL_MW_SENSOR_FUSION_MODE_COMPASS: + mbl_mw_acc_enable_acceleration_sampling(board); + mbl_mw_mag_bmm150_enable_b_field_sampling(board); + mbl_mw_acc_start(board); + mbl_mw_mag_bmm150_start(board); + break; + case MBL_MW_SENSOR_FUSION_MODE_M4G: + mbl_mw_acc_enable_acceleration_sampling(board); + mbl_mw_mag_bmm150_enable_b_field_sampling(board); + mbl_mw_acc_start(board); + mbl_mw_mag_bmm150_start(board); + break; + } + + uint8_t enable_cmd[4] = {MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::OUTPUT_ENABLE), + ((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->enable_mask, 0x0}; + send_command(board, enable_cmd, sizeof(enable_cmd)); + + uint8_t start_cmd[3] = {MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::ENABLE), 0x1}; + send_command(board, start_cmd, sizeof(start_cmd)); +} + +void mbl_mw_sensor_fusion_stop(const MblMwMetaWearBoard* board) { + uint8_t stop_cmd[3] = {MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::ENABLE), 0x0}; + send_command(board, stop_cmd, sizeof(stop_cmd)); + + uint8_t disable_cmd[4] = {MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::OUTPUT_ENABLE), 0x0, 0x7f}; + send_command(board, disable_cmd, sizeof(disable_cmd)); + + switch(((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->config.mode) { + case MBL_MW_SENSOR_FUSION_MODE_NDOF: + mbl_mw_acc_stop(board); + mbl_mw_gyro_bmi160_stop(board); + mbl_mw_mag_bmm150_stop(board); + mbl_mw_acc_disable_acceleration_sampling(board); + mbl_mw_gyro_bmi160_disable_rotation_sampling(board); + mbl_mw_mag_bmm150_disable_b_field_sampling(board); + break; + case MBL_MW_SENSOR_FUSION_MODE_IMU_PLUS: + mbl_mw_acc_stop(board); + mbl_mw_gyro_bmi160_stop(board); + mbl_mw_acc_disable_acceleration_sampling(board); + mbl_mw_gyro_bmi160_disable_rotation_sampling(board); + break; + case MBL_MW_SENSOR_FUSION_MODE_COMPASS: + mbl_mw_acc_stop(board); + mbl_mw_mag_bmm150_stop(board); + mbl_mw_acc_disable_acceleration_sampling(board); + mbl_mw_mag_bmm150_disable_b_field_sampling(board); + break; + case MBL_MW_SENSOR_FUSION_MODE_M4G: + mbl_mw_acc_stop(board); + mbl_mw_mag_bmm150_stop(board); + mbl_mw_acc_disable_acceleration_sampling(board); + mbl_mw_mag_bmm150_disable_b_field_sampling(board); + break; + } +} + +void mbl_mw_sensor_fusion_read_calibration_data(MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrCalibDataPtr completed) { + if (board->module_info.at(MBL_MW_MODULE_SENSOR_FUSION).revision < CALIB_DATA_REVISION) { + completed(context, board, nullptr); + } else { + transient_states[board].read_calib_data_context = context; + transient_states[board].read_calib_data_completed = completed; + + uint8_t command[2] = { MBL_MW_MODULE_SENSOR_FUSION, READ_REGISTER(ORDINAL(SensorFusionRegister::ACC_CAL_DATA)) }; + SEND_COMMAND; + } +} + +void mbl_mw_sensor_fusion_reset_orientation(MblMwMetaWearBoard* board) { + if (board->module_info.at(MBL_MW_MODULE_SENSOR_FUSION).revision >= RESET_ORIENTATION_REVISION) { + uint8_t reset_cmd[3] = {MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::RESET_ORIENTATION), 0x1}; + send_command(board, reset_cmd, sizeof(reset_cmd)); + } +} + +void mbl_mw_sensor_fusion_write_calibration_data(const MblMwMetaWearBoard* board, const MblMwCalibrationData* data) { + if (board->module_info.at(MBL_MW_MODULE_SENSOR_FUSION).revision >= CALIB_DATA_REVISION) { + uint8_t command[12] = { MBL_MW_MODULE_SENSOR_FUSION, ORDINAL(SensorFusionRegister::ACC_CAL_DATA) }; + memcpy(command + 2, data->acc, sizeof(command) - 2); + SEND_COMMAND; + + auto mode = ((SensorFusionState*) board->module_config.at(MBL_MW_MODULE_SENSOR_FUSION))->config.mode; + if (mode == MBL_MW_SENSOR_FUSION_MODE_IMU_PLUS || mode == MBL_MW_SENSOR_FUSION_MODE_NDOF) { + command[1] = ORDINAL(SensorFusionRegister::GYRO_CAL_DATA); + memcpy(command + 2, data->gyro, sizeof(command) - 2); + SEND_COMMAND; + } + + if (mode == MBL_MW_SENSOR_FUSION_MODE_M4G || mode == MBL_MW_SENSOR_FUSION_MODE_NDOF || mode == MBL_MW_SENSOR_FUSION_MODE_COMPASS) { + command[1] = ORDINAL(SensorFusionRegister::MAG_CAL_DATA); + memcpy(command + 2, data->mag, sizeof(command) - 2); + SEND_COMMAND; + } + } +} + +void create_sensor_fusion_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(SensorFusionRegister::CORRECTED_ACC): + uri << "corrected-acceleration"; + break; + case ORDINAL(SensorFusionRegister::CORRECTED_GYRO): + uri << "corrected-angular-velocity"; + break; + case ORDINAL(SensorFusionRegister::CORRECTED_MAG): + uri << "corrected-magnetic-field"; + break; + case ORDINAL(SensorFusionRegister::QUATERNION): + uri << "quaternion"; + break; + case ORDINAL(SensorFusionRegister::EULER_ANGLES): + uri << "euler-angles"; + break; + case ORDINAL(SensorFusionRegister::GRAVITY_VECTOR): + uri << "gravity"; + break; + case ORDINAL(SensorFusionRegister::LINEAR_ACC): + uri << "linear-acceleration"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion_private.h new file mode 100644 index 0000000..86cd35f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion_private.h @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +#include "metawear/core/metawearboard_fwd.h" + +void init_sensor_fusion_module(MblMwMetaWearBoard* board); +void free_sensor_fusion_module(MblMwMetaWearBoard* board); +void serialize_sensor_fusion_config(const MblMwMetaWearBoard *board, std::vector& state); +void deserialize_sensor_fusion_config(MblMwMetaWearBoard *board, uint8_t** state_stream); +void create_sensor_fusion_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion_register.h new file mode 100644 index 0000000..be3914c --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion_register.h @@ -0,0 +1,19 @@ +#pragma once + +enum class SensorFusionRegister : uint8_t { + ENABLE = 1, + MODE, + OUTPUT_ENABLE, + CORRECTED_ACC, + CORRECTED_GYRO, + CORRECTED_MAG, + QUATERNION, + EULER_ANGLES, + GRAVITY_VECTOR, + LINEAR_ACC, + CALIBRATION_STATE, + ACC_CAL_DATA, + GYRO_CAL_DATA, + MAG_CAL_DATA, + RESET_ORIENTATION +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough.cpp new file mode 100644 index 0000000..3e272b6 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough.cpp @@ -0,0 +1,144 @@ +#include "metawear/sensor/i2c.h" +#include "metawear/sensor/spi.h" +#include "serialpassthrough_private.h" +#include "serialpassthrough_register.h" +#include "utils.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/register.h" + +#include +#include + +using std::forward_as_tuple; +using std::memcpy; +using std::piecewise_construct; +using std::stringstream; +using std::vector; + +const uint8_t SPI_REVISION= 1; + +struct SpiBitFields { + uint8_t slave_select_pin, clock_pin, mosi_pin, miso_pin; + uint8_t lsb_first:1; + uint8_t mode:2; + uint8_t frequency:3; + uint8_t use_nrf_pins:1; + uint8_t :1; + + SpiBitFields(const MblMwSpiParameters* parameters); +}; + +SpiBitFields::SpiBitFields(const MblMwSpiParameters* parameters) { + memcpy(this, ¶meters->slave_select_pin, 4); + *(((uint8_t*) this) + 4)= 0; + lsb_first= parameters->lsb_first; + mode= parameters->mode; + frequency= parameters->frequency; + use_nrf_pins= parameters->use_nrf_pins; +} + +MblMwI2cSignal::MblMwI2cSignal(ResponseHeader header, MblMwMetaWearBoard* owner, uint8_t length) : + MblMwDataSignal(header, owner, DataInterpreter::BYTE_ARRAY, 1, length, 0, 0) { +} + +MblMwI2cSignal::MblMwI2cSignal(uint8_t** state_stream, MblMwMetaWearBoard *owner) : MblMwDataSignal(state_stream, owner) { +} + +void MblMwI2cSignal::read() const { +} + +void MblMwI2cSignal::read(const void* parameters) const { + const MblMwI2cReadParameters* read_parameters= (const MblMwI2cReadParameters*) parameters; + uint8_t command[6]= { header.module_id, header.register_id, read_parameters->device_addr, read_parameters->register_addr, header.data_id, length() }; + SEND_COMMAND_BOARD(owner); +} + +MblMwSpiSignal::MblMwSpiSignal(ResponseHeader header, MblMwMetaWearBoard* owner, uint8_t length) : + MblMwDataSignal(header, owner, DataInterpreter::BYTE_ARRAY, 1, length, 0, 0) { +} + +MblMwSpiSignal::MblMwSpiSignal(uint8_t** state_stream, MblMwMetaWearBoard *owner) : MblMwDataSignal(state_stream, owner) { +} + +void MblMwSpiSignal::read() const { +} + +void MblMwSpiSignal::read(const void* parameters) const { + const MblMwSpiParameters* read_parameters= (const MblMwSpiParameters*) parameters; + SpiBitFields fields(read_parameters); + + vector command= { header.module_id, header.register_id }; + command.insert(command.end(), (uint8_t*) &fields, ((uint8_t*) &fields) + sizeof(SpiBitFields)); + command.insert(command.end(), (length() - 1) | (header.data_id << 4)); + if (read_parameters->data != nullptr) { + command.insert(command.end(), read_parameters->data, read_parameters->data + read_parameters->data_length); + } + + send_command(owner, command.data(), (uint8_t) command.size()); +} + +void init_serialpassthrough_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_I2C) && board->module_info.at(MBL_MW_MODULE_I2C).present) { + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_I2C, READ_REGISTER(ORDINAL(SerialPassthroughRegister::I2C_READ_WRITE))), + forward_as_tuple(response_handler_data_with_id)); + + if (board->module_info.at(MBL_MW_MODULE_I2C).revision >= SPI_REVISION) { + board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_I2C, READ_REGISTER(ORDINAL(SerialPassthroughRegister::SPI_READ_WRITE))), + forward_as_tuple(response_handler_data_with_id)); + } + } +} + +MblMwDataSignal* mbl_mw_i2c_get_data_signal(MblMwMetaWearBoard *board, uint8_t length, uint8_t id) { + ResponseHeader header(MBL_MW_MODULE_I2C, READ_REGISTER(ORDINAL(SerialPassthroughRegister::I2C_READ_WRITE)), id); + + if (!board->module_events.count(header)) { + board->module_events[header]= new MblMwI2cSignal(header, board, length); + } + return dynamic_cast(board->module_events.at(header)); +} + +MblMwDataSignal* mbl_mw_spi_get_data_signal(MblMwMetaWearBoard* board, uint8_t length, uint8_t id) { + if (board->module_info.count(MBL_MW_MODULE_I2C) && board->module_info.at(MBL_MW_MODULE_I2C).present && + board->module_info.at(MBL_MW_MODULE_I2C).revision >= SPI_REVISION) { + ResponseHeader header(MBL_MW_MODULE_I2C, READ_REGISTER(ORDINAL(SerialPassthroughRegister::SPI_READ_WRITE)), id); + + if (!board->module_events.count(header)) { + board->module_events[header]= new MblMwSpiSignal(header, board, length); + } + return dynamic_cast(board->module_events.at(header)); + } + return nullptr; +} + +void mbl_mw_i2c_write(const MblMwMetaWearBoard *board, uint8_t device_addr, uint8_t register_addr, const uint8_t* value, uint8_t length) { + vector command= { MBL_MW_MODULE_I2C, ORDINAL(SerialPassthroughRegister::I2C_READ_WRITE), device_addr, register_addr, 0xff, length}; + command.insert(command.end(), value, value + length); + + send_command(board, command.data(), (uint8_t) command.size()); +} + +void mbl_mw_spi_write(const MblMwMetaWearBoard* board, const MblMwSpiParameters* parameters) { + const MblMwSpiParameters* read_parameters= (const MblMwSpiParameters*) parameters; + SpiBitFields fields(read_parameters); + + vector command= { MBL_MW_MODULE_I2C, ORDINAL(SerialPassthroughRegister::SPI_READ_WRITE) }; + command.insert(command.end(), (uint8_t*) &fields, ((uint8_t*) &fields) + sizeof(SpiBitFields)); + command.insert(command.end(), read_parameters->data, read_parameters->data + read_parameters->data_length); + + send_command(board, command.data(), (uint8_t) command.size()); +} + +void create_serialpassthrough_uri(const MblMwDataSignal* signal, std::stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(SerialPassthroughRegister::I2C_READ_WRITE): + uri << "i2c[" << (int) signal->header.data_id << "]"; + break; + case ORDINAL(SerialPassthroughRegister::SPI_READ_WRITE): + uri << "spi[" << (int) signal->header.data_id << "]"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough_private.h new file mode 100644 index 0000000..178b23d --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough_private.h @@ -0,0 +1,24 @@ +#pragma once + +#include "metawear/core/cpp/datasignal_private.h" + +#include + +struct MblMwI2cSignal : public MblMwDataSignal { + MblMwI2cSignal(ResponseHeader header, MblMwMetaWearBoard* owner, uint8_t length); + MblMwI2cSignal(uint8_t** state_stream, MblMwMetaWearBoard *owner); + + virtual void read() const; + virtual void read(const void* parameters) const; +}; + +struct MblMwSpiSignal : public MblMwDataSignal { + MblMwSpiSignal(ResponseHeader header, MblMwMetaWearBoard* owner, uint8_t length); + MblMwSpiSignal(uint8_t** state_stream, MblMwMetaWearBoard *owner); + + virtual void read() const; + virtual void read(const void* parameters) const; +}; + +void init_serialpassthrough_module(MblMwMetaWearBoard *board); +void create_serialpassthrough_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough_register.h new file mode 100644 index 0000000..2c01fdb --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough_register.h @@ -0,0 +1,6 @@ +#pragma once + +enum class SerialPassthroughRegister : uint8_t { + I2C_READ_WRITE= 1, + SPI_READ_WRITE, +}; diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch.cpp new file mode 100644 index 0000000..4ab02f8 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch.cpp @@ -0,0 +1,35 @@ +#include "metawear/sensor/switch.h" +#include "switch_register.h" + +#include "metawear/core/module.h" +#include "metawear/core/cpp/metawearboard_def.h" +#include "metawear/core/cpp/datasignal_private.h" +#include "metawear/core/cpp/register.h" +#include "metawear/core/cpp/responseheader.h" + +using std::stringstream; + +const ResponseHeader SWITCH_RESPONSE_HEADER(MBL_MW_MODULE_SWITCH, ORDINAL(SwitchRegister::STATE)); + +MblMwDataSignal* mbl_mw_switch_get_state_data_signal(const MblMwMetaWearBoard *board) { + return dynamic_cast(board->module_events.at(SWITCH_RESPONSE_HEADER)); +} + +void init_switch_module(MblMwMetaWearBoard *board) { + if (board->module_info.count(MBL_MW_MODULE_SWITCH) && board->module_info.at(MBL_MW_MODULE_SWITCH).present) { + if (!board->module_events.count(SWITCH_RESPONSE_HEADER)) { + board->module_events[SWITCH_RESPONSE_HEADER] = new MblMwDataSignal(SWITCH_RESPONSE_HEADER, board, DataInterpreter::UINT32, + 1, 1, 0, 0); + } + + board->responses[SWITCH_RESPONSE_HEADER] = response_handler_data_no_id; + } +} + +void create_switch_uri(const MblMwDataSignal* signal, stringstream& uri) { + switch(CLEAR_READ(signal->header.register_id)) { + case ORDINAL(SwitchRegister::STATE): + uri << "switch"; + break; + } +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch_private.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch_private.h new file mode 100644 index 0000000..88e6355 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch_private.h @@ -0,0 +1,7 @@ +#pragma once + +#include "metawear/core/metawearboard_fwd.h" +#include + +void init_switch_module(MblMwMetaWearBoard *board); +void create_switch_uri(const MblMwDataSignal* signal, std::stringstream& uri); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch_register.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch_register.h new file mode 100644 index 0000000..8051442 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch_register.h @@ -0,0 +1,6 @@ +#pragma once + +enum class SwitchRegister : uint8_t { + STATE = 1 +}; + diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.cpp b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.cpp new file mode 100644 index 0000000..d3dbfaa --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.cpp @@ -0,0 +1,42 @@ +#include "utils.h" + +#include +#include +#include +#include +#include + +using std::distance; +using std::fabs; +using std::min_element; +using std::sprintf; +using std::strcpy; +using std::strlen; +using std::transform; +using std::vector; + +char* copy_string_index(const char* src, std::uint8_t i) { + char* buffer = (char*)std::malloc(strlen(src) + 6); + sprintf(buffer, "%s[%d]", src, i); + return buffer; +} + +char* copy_string(const char* src) { + char* buffer = (char*)std::malloc(strlen(src) + 1); + strcpy(buffer, src); + return buffer; +} + +uint8_t closest_index(const vector& values, float key) { + return closest_index(values.data(), values.size(), key); +} + +uint8_t closest_index(const float* values, size_t len, float key) { + vector differences; + differences.resize(len); + + transform(values, values + len, differences.begin(), [key](const float val) { + return fabs(val - key); + }); + return distance(differences.begin(), min_element(differences.begin(), differences.end())); +} diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.h new file mode 100644 index 0000000..6b321cc --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include + +char* copy_string_index(const char* src, std::uint8_t i); +char* copy_string(const char* src); + +uint8_t closest_index(const std::vector& values, float key); +uint8_t closest_index(const float* values, std::size_t len, float key); \ No newline at end of file diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/gpio.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/gpio.h new file mode 100644 index 0000000..874bae4 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/gpio.h @@ -0,0 +1,130 @@ +/** + * @copyright MbientLab License + * @file gpio.h + * @brief Interacts with the general purpose I/O pins on the board + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Pin value indicating the pin setting is not used */ +const uint8_t MBL_MW_GPIO_UNUSED_PIN = 0xff; + +/** + * Pin configuration types + */ +typedef enum { + MBL_MW_GPIO_PULL_MODE_UP= 0, + MBL_MW_GPIO_PULL_MODE_DOWN, + MBL_MW_GPIO_PULL_MODE_NONE +} MblMwGpioPullMode; + +/** + * Read modes for analog input + */ +typedef enum { + MBL_MW_GPIO_ANALOG_READ_MODE_ABS_REF= 0, ///< Read input voltage as an absolute reference + MBL_MW_GPIO_ANALOG_READ_MODE_ADC ///< Read input voltage as a supply ratio +} MblMwGpioAnalogReadMode; + +/** + * Pin change types + */ +typedef enum { + MBL_MW_GPIO_PIN_CHANGE_TYPE_RISING= 1, ///< Notify on rising edge of a change + MBL_MW_GPIO_PIN_CHANGE_TYPE_FALLING, ///< Notify on falling edge of a change + MBL_MW_GPIO_PIN_CHANGE_TYPE_ANY ///< Notify on any edge of a change +} MblMwGpioPinChangeType; + +/** + * Additional parameters required for an enhanced analog read. + * This struct is to be used with mbl_mw_datasignal_read_with_parameters + * @author Eric Tsai + */ +typedef struct { + uint8_t pullup_pin; ///< GPIO pin to be pulled up before the read, set to MBL_MW_GPIO_UNUSED_PIN if not used + uint8_t pulldown_pin; ///< GPIO pin to be pulled down before the read, set to MBL_MW_GPIO_UNUSED_PIN if not used + uint8_t virtual_pin; ///< GPIO pin the data identifies as, must match pin value for mbl_mw_gpio_get_analog_input_data_signal if used or set to MBL_MW_GPIO_UNUSED_PIN if not used + uint16_t delay_us; ///< How long to wait before reading from the pin, between [0, 1020]us, set to 0 if not used +} MblMwGpioAnalogReadParameters; + +/** + * Retrieves a data signal representing analog data + * See MblMwGpioAnalogReadMode for allowed mode values and see MetaWear datasheet for allowed pin values + * @param board Board to receive data from + * @param pin GPIO pin to read + * @param mode Read mode to use + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_gpio_get_analog_input_data_signal(MblMwMetaWearBoard* board, uint8_t pin, MblMwGpioAnalogReadMode mode); +/** + * Retrieves a data signal representing digital data + * See MetaWear datasheet for allowed pin values + * @param board Board to receive data from + * @param pin GPIO pin to read + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_gpio_get_digital_input_data_signal(MblMwMetaWearBoard* board, uint8_t pin); +/** + * Retrieves a data signal representing changes in digital data + * The monitor provides a callback anytime the value changes + * See MetaWear datasheet for allowed pin values + * @param board Board to receive data from + * @param pin GPIO pin to monitor + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_gpio_get_pin_monitor_data_signal(MblMwMetaWearBoard* board, uint8_t pin); +/** + * Sets the pin pull mode + * A GPIO pin can be pulled up (to high voltage), pulled down (to 0V), or left floating. + * See MblMwGpioPullMode for allowed mode values + * @param board Board the pin is on + * @param pin GPIO pin to modify + * @param mode New pull mode + */ +METAWEAR_API void mbl_mw_gpio_set_pull_mode(const MblMwMetaWearBoard* board, uint8_t pin, MblMwGpioPullMode mode); +/** + * Sets the digital output state + * The GPIO pin is set as an output pin and turned on (high voltage) + * See MetaWear datasheet for allowed pin values + * @param board Board the pin is on + * @param pin GPIO pin to set + */ +METAWEAR_API void mbl_mw_gpio_set_digital_output(const MblMwMetaWearBoard* board, uint8_t pin); +/** + * Clears the digital output state + * The GPIO pin is set as an output pin and turned off (0 voltage) + * See MetaWear datasheet for allowed pin values + * @param board Board the pin is on + * @param pin GPIO pin to clear + */ +METAWEAR_API void mbl_mw_gpio_clear_digital_output(const MblMwMetaWearBoard* board, uint8_t pin); +/** + * Sets the pin change type to monitor + * The monitor provides a callback anytime the value changes by MblMwGpioPinChangeType when pin monitoring is on + * See MblMwGpioPinChangeType for allowed type values and see MetaWear datasheet for allowed pin values + * @param board Board the pin is on + * @param pin GPIO pin to set + * @param type Change type to monitor + */ +METAWEAR_API void mbl_mw_gpio_set_pin_change_type(const MblMwMetaWearBoard* board, uint8_t pin, MblMwGpioPinChangeType type); +/** + * Start pin monitoring + * @param board Board the pin is on + * @param pin GPIO pin to monitor + */ +METAWEAR_API void mbl_mw_gpio_start_pin_monitoring(const MblMwMetaWearBoard* board, uint8_t pin); +/** + * Stop pin monitoring + * @param board Board the pin is on + * @param pin GPIO pin to stop monitoring + */ +METAWEAR_API void mbl_mw_gpio_stop_pin_monitoring(const MblMwMetaWearBoard* board, uint8_t pin); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/gyro_bosch.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/gyro_bosch.h new file mode 100644 index 0000000..8873ea1 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/gyro_bosch.h @@ -0,0 +1,200 @@ +/** + * @copyright MbientLab License + * @file gyro_bosch.h + * @brief Functions for interacting with the BMI160 and BMI270 gyro. + * @details This sensor is only available on MMR, MMS, MetaWear RG and RPro boards. + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//@{ +/** Indices for component values of the rotation data signal, used with mbl_mw_datasignal_get_component */ +const uint8_t MBL_MW_GYRO_ROTATION_X_AXIS_INDEX = 0, + MBL_MW_GYRO_ROTATION_Y_AXIS_INDEX = 1, + MBL_MW_GYRO_ROTATION_Z_AXIS_INDEX = 2; +//@} + +/** + * Available output data rates on the BMI160 gyro + */ +typedef enum { + MBL_MW_GYRO_BOSCH_ODR_25Hz= 6, + MBL_MW_GYRO_BOSCH_ODR_50Hz, + MBL_MW_GYRO_BOSCH_ODR_100Hz, + MBL_MW_GYRO_BOSCH_ODR_200Hz, + MBL_MW_GYRO_BOSCH_ODR_400Hz, + MBL_MW_GYRO_BOSCH_ODR_800Hz, + MBL_MW_GYRO_BOSCH_ODR_1600Hz, + MBL_MW_GYRO_BOSCH_ODR_3200Hz +} MblMwGyroBoschOdr; + +/** + * Available degrees per second ranges on the BMI160 gyro + */ +typedef enum { + MBL_MW_GYRO_BOSCH_RANGE_2000dps= 0, ///< +/-2000 degrees per second + MBL_MW_GYRO_BOSCH_RANGE_1000dps, ///< +/-1000 degrees per second + MBL_MW_GYRO_BOSCH_RANGE_500dps, ///< +/-500 degrees per second + MBL_MW_GYRO_BOSCH_RANGE_250dps, ///< +/-250 degrees per second + MBL_MW_GYRO_BOSCH_RANGE_125dps ///< +/-125 degrees per second +} MblMwGyroBoschRange; + +/** + * Retrieves the data signal representing BMI160 rotation data + * This signal is timestamp,x,y,z gyro data + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI160 rotation data signal + * MblMwCartesianFloat is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_gyro_bmi160_get_rotation_data_signal(const MblMwMetaWearBoard *board); +/** + * Retrieves the data signal representing BMI270 rotation data + * This signal is timestamp,x,y,z gyro data + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the board's BMI160 rotation data signal + * MblMwCartesianFloat is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_gyro_bmi270_get_rotation_data_signal(const MblMwMetaWearBoard *board); +/** + * @deprecated As of v0.8.0 and will be removed in v1.0.0. Use mbl_mw_gyro_bmi160_get_packed_rotation_data_signal instead. + */ +METAWEAR_API MblMwDataSignal* mbl_mw_gyro_bmi160_get_high_freq_rotation_data_signal(const MblMwMetaWearBoard *board); +/** + * Variant of rotation data that packs multiple data samples into 1 BLE packet to increase the + * data throughput. This data signal cannot be used with data processing or logging, only with streaming. + * This signal is timestamp,x,y,z,x,y,z,x,y,z gyro data (it packs three acc data points in one timestamp) + * @return Pointer to the data singal + * [MblMwCartesianFloat, MblMwCartesianFloat, MblMwCartesianFloat] is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_gyro_bmi160_get_packed_rotation_data_signal(const MblMwMetaWearBoard *board); +/** + * Variant of rotation data that packs multiple data samples into 1 BLE packet to increase the + * data throughput. This data signal cannot be used with data processing or logging, only with streaming. + * This signal is timestamp,x,y,z,x,y,z,x,y,z acc gyro (it packs three acc data points in one timestamp) + * @return Pointer to the data singal + * [MblMwCartesianFloat, MblMwCartesianFloat, MblMwCartesianFloat] is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_gyro_bmi270_get_packed_rotation_data_signal(const MblMwMetaWearBoard *board); +/** + * Sets the output data rate for the BMI160 gyroscope + * The ODR sets the output data frequency in Hz. + * See MblMwGyroBoschOdr for allowed values. + * @param board Pointer to the board to modify + * @param odr Output data rate value to assign + */ +METAWEAR_API void mbl_mw_gyro_bmi160_set_odr(MblMwMetaWearBoard *board, MblMwGyroBoschOdr odr); +/** + * Sets the rotation range + * The range is in units of degrees per second (dps) for Bosch sensors + * See MblMwGyroBoschRange for allowed values. + * @param board Pointer to the board to modify + * @param range New rotation range + */ +METAWEAR_API void mbl_mw_gyro_bmi160_set_range(MblMwMetaWearBoard *board, MblMwGyroBoschRange range); +/** + * Writes the configuration to the sendor + * Applies the ODR and RANGE values set in set_range() and set_odr(). + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi160_write_config(const MblMwMetaWearBoard *board); +/** + * Pulls the current gyro output data rate and data range from the sensor + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param completed Callback function that is executed when the task is finished + */ +METAWEAR_API void mbl_mw_gyro_bmi160_read_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed); +/** + * Sets the output data rate for the BMI270 gyroscope + * The ODR sets the output data frequency in Hz. + * See MblMwGyroBoschOdr for allowed values. + * @param board Pointer to the board to modify + * @param odr Output data rate value to assign + */ +METAWEAR_API void mbl_mw_gyro_bmi270_set_odr(MblMwMetaWearBoard *board, MblMwGyroBoschOdr odr); +/** + * Sets the rotation range for the BMI270 gyroscope + * The range is in units of degrees per second (dps) for Bosch sensors + * See MblMwGyroBoschRange for allowed values. + * @param board Pointer to the board to modify + * @param range New rotation range + */ +METAWEAR_API void mbl_mw_gyro_bmi270_set_range(MblMwMetaWearBoard *board, MblMwGyroBoschRange range); +/** + * Writes the configuration to the sendor + * Applies the ODR and RANGE values set in set_range() and set_odr(). + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi270_write_config(const MblMwMetaWearBoard *board); +/** + * Pulls the current gyro output data rate and data range from the sensor + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param completed Callback function that is executed when the task is finished + */ +METAWEAR_API void mbl_mw_gyro_bmi270_read_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed); +/** + * Switches the gyro to active mode. + * While in active mode, the gyro cannot be configured + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi160_start(const MblMwMetaWearBoard *board); +/** + * Switches the gyro to standby mode. + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi160_stop(const MblMwMetaWearBoard *board); +/** + * Switches the gyro to active mode. + * While in active mode, the gyro cannot be configured + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi270_start(const MblMwMetaWearBoard *board); +/** + * Switches the gyro to standby mode. + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi270_stop(const MblMwMetaWearBoard *board); +/** + * Enables rotation sampling + * The board will start gathering data from the gyroscope + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi160_enable_rotation_sampling(const MblMwMetaWearBoard *board); +/** + * Disables rotation sampling + * The board will stop gathering data from the gyroscope + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi160_disable_rotation_sampling(const MblMwMetaWearBoard *board); +/** + * Enables rotation sampling + * The board will start gathering data from the gyroscope + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi270_enable_rotation_sampling(const MblMwMetaWearBoard *board); +/** + * Disables rotation sampling + * The board will stop gathering data from the gyroscope + * @param board Pointer to the board to send the command to + */ +METAWEAR_API void mbl_mw_gyro_bmi270_disable_rotation_sampling(const MblMwMetaWearBoard *board); +/** + * Manual compensation for the BMI270 gyro + * The offset compensation field for each axis has a width of 10 bit using two’s complement notation. + * The offset resolution (LSB) is 61 mdps and the offset range is +- 31 dps. + * @param board Pointer to the board to send the command to + * @param x_offset Offset compensation for Gyroscope X-axis + * @param y_offset Offset compensation for Gyroscope Y-axis + * @param z_offset Offset compensation for Gyroscope Z-axis + */ +METAWEAR_API void mbl_mw_gyro_bmi270_acc_offsets(const MblMwMetaWearBoard* board, uint8_t x_offset, uint8_t y_offset, uint8_t z_offset); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/humidity_bme280.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/humidity_bme280.h new file mode 100644 index 0000000..5c4370f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/humidity_bme280.h @@ -0,0 +1,45 @@ +/** + * @copyright MbientLab License (LICENSE.md) + * @file humidity_bme280.h + * @brief Communicates with the BME280 humidity sensor, only available on MetaEnvironment boards + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Supported oversampling modes on the BME280 humidity sensor + */ +typedef enum { + MBL_MW_HUMIDITY_BME280_OVERSAMPLING_1X= 1, + MBL_MW_HUMIDITY_BME280_OVERSAMPLING_2X, + MBL_MW_HUMIDITY_BME280_OVERSAMPLING_4X, + MBL_MW_HUMIDITY_BME280_OVERSAMPLING_8X, + MBL_MW_HUMIDITY_BME280_OVERSAMPLING_16X +} MblMwHumidityBme280Oversampling; + +/** + * Retrieves the data signal representing humidity data + * Relative humidity is returned as a percentage. + * @param board Board the humidity sensor resides on + * @return Pointer to the data signal + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_humidity_bme280_get_percentage_data_signal(const MblMwMetaWearBoard *board); +/** + * Sets the oversampling mode + * For the humidity measurement, oversampling is possible to reduce the noise. + * The resolution of the humidity measurement is fixed at 16 bit ADC output. + * See MblMwHumidityBme280Oversampling for allowed oversampling values + * @param board Board the humidity sensor resides on + * @param oversampling New oversampling mode + */ +METAWEAR_API void mbl_mw_humidity_bme280_set_oversampling(const MblMwMetaWearBoard *board, MblMwHumidityBme280Oversampling oversampling); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/i2c.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/i2c.h new file mode 100644 index 0000000..1a37538 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/i2c.h @@ -0,0 +1,44 @@ +/** + * @copyright MbientLab License (LICENSE.md) + * @file i2c.h + * @brief Communicates with sensors on the I2C bus + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Parameters required for an i2c read. + * This struct is to be used with mbl_mw_datasignal_read_with_parameters + */ +typedef struct { + uint8_t device_addr; ///< Device to communicate with + uint8_t register_addr; ///< Register to read from +} MblMwI2cReadParameters; + +/** + * Retrieves the data signal representing i2c data + * The data signal is identified by the id value and if the id is not present, a new data signal will be created using the length parameter. + * @param board Board the i2c bus resides on + * @param length Number of bytes to read + * @param id Numerical value identifying the data + * @return Pointer to the i2c data signal + */ +METAWEAR_API MblMwDataSignal* mbl_mw_i2c_get_data_signal(MblMwMetaWearBoard *board, uint8_t length, uint8_t id); +/** + * Writes data via the i2c bus + * @param board Board the i2c bus resides on + * @param device_addr Device to write to + * @param register_addr Address of the register to write + * @param value Payload, as a byte array + * @param length Number of bytes + */ +METAWEAR_API void mbl_mw_i2c_write(const MblMwMetaWearBoard *board, uint8_t device_addr, uint8_t register_addr, const uint8_t* value, uint8_t length); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/magnetometer_bmm150.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/magnetometer_bmm150.h new file mode 100644 index 0000000..2e2ea2f --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/magnetometer_bmm150.h @@ -0,0 +1,141 @@ +/** + * @copyright MbientLab License (LICENSE.md) + * @file magnetometer_bmm150.h + * @brief Communicates with the BMM150 magnetometer + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//@{ +/** Indices for component values of the bfield data signal, used with mbl_mw_datasignal_get_component */ +const uint8_t MBL_MW_MAG_BFIELD_X_AXIS_INDEX = 0, + MBL_MW_MAG_BFIELD_Y_AXIS_INDEX = 1, + MBL_MW_MAG_BFIELD_Z_AXIS_INDEX = 2; +//@} + +/** + * Preset power modes recommended by Bosch + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
SettingODRAverage CurrentNoise
LOW_POWER10Hz170μA1.0μT (xy axis), 1.4μT (z axis)
REGULAR10Hz0.5mA0.6μT
ENHANCED_REGULAR10Hz0.8mA0.5μT
HIGH_ACCURACY20Hz4.9mA0.3μT
+ */ +typedef enum { + MBL_MW_MAG_BMM150_PRESET_LOW_POWER= 0, + MBL_MW_MAG_BMM150_PRESET_REGULAR, + MBL_MW_MAG_BMM150_PRESET_ENHANCED_REGULAR, + MBL_MW_MAG_BMM150_PRESET_HIGH_ACCURACY +} MblMwMagBmm150Preset; + +/** + * Available output data rates for the BMM150 magnetometer + */ +typedef enum { + MBL_MW_MAG_BMM150_ODR_10Hz = 0, + MBL_MW_MAG_BMM150_ODR_2Hz, + MBL_MW_MAG_BMM150_ODR_6Hz, + MBL_MW_MAG_BMM150_ODR_8Hz, + MBL_MW_MAG_BMM150_ODR_15Hz, + MBL_MW_MAG_BMM150_ODR_20Hz, + MBL_MW_MAG_BMM150_ODR_25Hz, + MBL_MW_MAG_BMM150_ODR_30Hz +} MblMwMagBmm150Odr; + +/** + * Retrieves the data signal representing B field strength in uT (micro Teslas) + * This signal is timestamp,x,y,z mag data + * @param board Calling object + * @return Pointer to the data signal + * MblMwCartesianFloat is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_mag_bmm150_get_b_field_data_signal(const MblMwMetaWearBoard *board); +/** + * Variant of B field data that packs multiple data samples into 1 BLE packet to increase the + * data throughput. This data signal cannot be used with data processing or logging, only with streaming. + * This signal is timestamp,x,y,z,x,y,z,x,y,z mag data (it packs three mag data points in one timestamp) + * @param board Calling object + * @return Pointer to the data signal + * [MblMwCartesianFloat, MblMwCartesianFloat, MblMwCartesianFloat] is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_mag_bmm150_get_packed_b_field_data_signal(const MblMwMetaWearBoard *board); +/** + * Manually configure the sensor, only for advanced users. + * It is recommended that users use one of the preset configurations. + * @param board Calling object + * @param xy_reps Repetitions on the x/y-axis + * @param z_reps Repetitions on the z-axis + * @param odr Sensor data rate + */ +METAWEAR_API void mbl_mw_mag_bmm150_configure(const MblMwMetaWearBoard *board, uint16_t xy_reps, uint16_t z_reps, MblMwMagBmm150Odr odr); +/** + * Sets the power mode to one of the recommended presets + * The BMM150 magnetometer part has four power modes, see MblMwMagBmm150Preset for values + * @param board Calling object + * @param preset New preset power mode to use + */ +METAWEAR_API void mbl_mw_mag_bmm150_set_preset(const MblMwMetaWearBoard *board, MblMwMagBmm150Preset preset); +/** + * Enable B field sampling + * The board will start gathering data from the magnetometer + * @param board Calling object + */ +METAWEAR_API void mbl_mw_mag_bmm150_enable_b_field_sampling(const MblMwMetaWearBoard *board); +/** + * Disable B field sampling + * The board will stop gathering data from the magnetometer + * @param board Calling object + */ +METAWEAR_API void mbl_mw_mag_bmm150_disable_b_field_sampling(const MblMwMetaWearBoard *board); +/** + * Switches the magnetometer into normal mode + * @param board Calling object + */ +METAWEAR_API void mbl_mw_mag_bmm150_start(const MblMwMetaWearBoard *board); +/** + * Switches the magnetometer into sleep mode + * @param board Calling object + */ +METAWEAR_API void mbl_mw_mag_bmm150_stop(const MblMwMetaWearBoard *board); +/** + * Puts the magnetometer in suspend mode. This function will not issuee the command unless the + * board is running minimum firmware v1.3.4. + * @param board Calling object + */ +METAWEAR_API void mbl_mw_mag_bmm150_suspend(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/multichanneltemperature.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/multichanneltemperature.h new file mode 100644 index 0000000..0a64468 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/multichanneltemperature.h @@ -0,0 +1,82 @@ +/** + * @copyright MbientLab License + * @file multichanneltemperature.h + * @brief Interacts with various temperature sources. + * @details The functions in the file only work for boards running firmware v1.0.4 or higher + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Enumeration of the available temperature sourcs. Note that not all sources are present + * on all boards + */ +typedef enum { + MBL_MW_TEMPERATURE_SOURCE_INVALID= -1, ///< Invalid temperature source + MBL_MW_TEMPERATURE_SOURCE_NRF_DIE= 0, ///< Temperature from the nRF chip + MBL_MW_TEMPERATURE_SOURCE_EXT_THERM, ///< Tempertaure from an external thermistor + MBL_MW_TEMPERATURE_SOURCE_BMP280, ///< Temperature from the BMP280 sensor + MBL_MW_TEMPERATURE_SOURCE_PRESET_THERM ///< Temperature from an internal thremistor +} MblMwTemperatureSource; + +/** + * Channel IDs for the temperature sources on the MetaWear R board + */ +typedef enum { + MBL_MW_METAWEAR_R_CHANNEL_ON_DIE= 0, ///< Temperature from the nRF chip + MBL_MW_METAWEAR_R_CHANNEL_EXT_THERMISTOR ///< Temperature from an external thermistor +} MblMwMetaWearRChannel; + +/** + * CHannel IDs for the temperature sources on the MetaWear RPro board + */ +typedef enum { + MBL_MW_METAWEAR_RPRO_CHANNEL_ON_DIE = 0, ///< Temperature from the nRF chip + MBL_MW_METAWEAR_RPRO_CHANNEL_ON_BOARD_THERMISTOR, ///< Temperature from the on board thermistor + MBL_MW_METAWEAR_RPRO_CHANNEL_EXT_THERMISTOR, ///< Temperature from an external thermistor + MBL_MW_METAWEAR_RPRO_CHANNEL_BMP280 ///< Temperature from the BMP280 sensor +} MblMwMetaWearRProChannel; + +/** + * Retrieves the data signal representing a temperature source + * The temperature is in C by default + * The temperature sensor can by the selected; it can be the on die sensor that is built in to the MCU, + * the on board thermistor, an external thermistor added to the GPIOs of the board or the BMP280. + * Each board comes with a different configuration of temperature sensors, refer to the datasheet of your MetaWear. + * @param board Board to retrieve the signal from + * @param channel Channel ID of the temperature source + * INT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_multi_chnl_temp_get_temperature_data_signal(const MblMwMetaWearBoard *board, uint8_t channel); +/** + * Configure the external thermistor + * If a thermistor is added to the GPIOs of the MetaWear, this function will enable the configuration + * @param board Board the external thermistor is attached to + * @param channel Channel ID of the external thermistor + * @param data_pin GPIO pin reading the data + * @param pulldown_pin GPIO pin the pulldown resistor is connected to + * @param active_high Zero if the pulldown pin is not active high, non-zero if active high + */ +METAWEAR_API void mbl_mw_multi_chnl_temp_configure_ext_thermistor(const MblMwMetaWearBoard *board, uint8_t channel, uint8_t data_pin, + uint8_t pulldown_pin, uint8_t active_high); +/** + * Retrieve the temperature source type corresponding to a channel ID + * @param board Board to lookup the temperature source on + * @param channel Channel ID to lookup + * @return Source type of the channel ID, MBL_MW_TEMP_SOURCE_INVALID if channel ID is out of range + */ +METAWEAR_API MblMwTemperatureSource mbl_mw_multi_chnl_temp_get_source(const MblMwMetaWearBoard *board, uint8_t channel); +/** + * Retrieve the number of available channels + * @return Number of channel IDs + */ +METAWEAR_API uint8_t mbl_mw_multi_chnl_temp_get_num_channels(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/proximity_tsl2671.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/proximity_tsl2671.h new file mode 100644 index 0000000..1c2c0e7 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/proximity_tsl2671.h @@ -0,0 +1,85 @@ +/** + * @copyright MbientLab License (LICENSE.md) + * @file proximity_tsl2671.h + * @brief Communicates with the TSL2671 proximity detector + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Photodiodes the detector should use for proximity detection + */ +typedef enum { + MBL_MW_PROXIMITY_TSL2671_CHANNEL_0= 1, ///< Use channel 0, which is responsive to infrared and visible light + MBL_MW_PROXIMITY_TSL2671_CHANNEL_1, ///< Use channel 1, which is responsive to primarily infrared light + MBL_MW_PROXIMITY_TSL2671_CHANNEL_BOTH ///< Use both channel 0 and 1 +} MblMwProximityTsl2671Channel; + +/** + * Amount of current driving the IR transmitter + */ +typedef enum { + MBL_MW_PROXIMITY_TSL2671_CURRENT_100mA= 0, + MBL_MW_PROXIMITY_TSL2671_CURRENT_50mA, + MBL_MW_PROXIMITY_TSL2671_CURRENT_25mA, + MBL_MW_PROXIMITY_TSL2671_CURRENT_12_5mA +} MblMwProximityTsl2671Current; + +/** + * Retrieves the data signal representing ADC values for the proximity of an object to the MetaWear + * @param board Board the sensor resides on + * @return Pointer to the data signal + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_proximity_tsl2671_get_adc_data_signal(const MblMwMetaWearBoard *board); +/** + * Sets the integration time + * The proximity integration time (PTIME) is the period of time that the internal ADC converts the analog signal to a digital count. + * It is recommend that this be set to a minimum of PTIME = 0xFF or 2.72 ms. + * @param board Board to modify + * @param time New integration time to use, between [2.72, 693.6] milliseconds + */ +METAWEAR_API void mbl_mw_proximity_tsl2671_set_integration_time(MblMwMetaWearBoard *board, float time); +/** + * Sets the pulse count. Sensitivity increase by the sqrt of pulse count. + * The proximity pulse count register sets the number of proximity pulses that will be transmitted. + * PPULSE defines the number of pulses to be transmitted at a 62.5-kHz rate. + * While the value can be programmed up to 255 pulses, the practical limit of the device is 32 pulses. + * It is recommended that 32 or fewer pulses be used to achieve maximum signal-to-noise ratio. + * @param board Board to modify + * @param n_pulses Number of pulses to use for proximity detection, between [1, 255] + */ +METAWEAR_API void mbl_mw_proximity_tsl2671_set_n_pulses(MblMwMetaWearBoard *board, uint8_t n_pulses); +/** + * Sets the photodiode that responds to light to be used + * Channel 0 photodiode (CH0), which is responsive to both visible and infrared light + * Channel 1 photodiode (CH1), which is responsive primarily to infrared light + * See MblMwProximityTsl2671Channel for allowed values + * @param board Board to modify + * @param channel New receiver channel to use + */ +METAWEAR_API void mbl_mw_proximity_tsl2671_set_receiver_channel(MblMwMetaWearBoard *board, MblMwProximityTsl2671Channel channel); +/** + * Sets the current driving the light transmitter. + * An internal LED driver can be configured to provide a constant current sink of 12.5 mA, 25 mA, 50 mA, or 100 mA of current. + * For boards powered by the CR2032 battery, it is recommended that the current be 25mA or less. + * See MblMwProximityTsl2671Current for allowed values + * @param board Board to modify + * @param current New driver current to use + */ +METAWEAR_API void mbl_mw_proximity_tsl2671_set_transmitter_current(MblMwMetaWearBoard *board, MblMwProximityTsl2671Current current); +/** + * Writes the configuration to the sensor + * Applies the INTEGRATION TIME, RECEIVER CHANNEL, PULSES and CURRENT values set in set_*(). + * @param board Board the sensor resides on + */ +METAWEAR_API void mbl_mw_proximity_tsl2671_write_config(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/sensor_common.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/sensor_common.h new file mode 100644 index 0000000..125a252 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/sensor_common.h @@ -0,0 +1,5 @@ +#include + +#include "metawear/core/datasignal_fwd.h" +#include "metawear/core/metawearboard_fwd.h" +#include "metawear/platform/dllmarker.h" diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/sensor_fusion.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/sensor_fusion.h new file mode 100644 index 0000000..34c7eff --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/sensor_fusion.h @@ -0,0 +1,182 @@ +/** + * @copyright MbientLab License + * @file sensor_fusion.h + * @brief Performs sensor fusion using accelerometer, gyro, and magnetometer data + * @details When using the sensor fusion module, do not use the accelerometer, gyro, and magnetometer functions. + * The api will automatically configure the sensors based on the selected fusion mode. + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const uint8_t MBL_MW_SENSOR_FUSION_CALIBRATION_ACCURACY_UNRELIABLE = 0, + MBL_MW_SENSOR_FUSION_CALIBRATION_ACCURACY_LOW = 1, + MBL_MW_SENSOR_FUSION_CALIBRATION_ACCURACY_MEDIUM = 2, + MBL_MW_SENSOR_FUSION_CALIBRATION_ACCURACY_HIGH = 3; + +/** + * Fusion modes supported by the algorithm + */ +typedef enum { + MBL_MW_SENSOR_FUSION_MODE_SLEEP = 0, + MBL_MW_SENSOR_FUSION_MODE_NDOF, + MBL_MW_SENSOR_FUSION_MODE_IMU_PLUS, + MBL_MW_SENSOR_FUSION_MODE_COMPASS, + MBL_MW_SENSOR_FUSION_MODE_M4G +} MblMwSensorFusionMode; + +/** + * Supported acceleration ranges + */ +typedef enum { + MBL_MW_SENSOR_FUSION_ACC_RANGE_2G = 0, + MBL_MW_SENSOR_FUSION_ACC_RANGE_4G, + MBL_MW_SENSOR_FUSION_ACC_RANGE_8G, + MBL_MW_SENSOR_FUSION_ACC_RANGE_16G +} MblMwSensorFusionAccRange; + +/** + * Supported rotation ranges + */ +typedef enum { + MBL_MW_SENSOR_FUSION_GYRO_RANGE_2000DPS = 0, + MBL_MW_SENSOR_FUSION_GYRO_RANGE_1000DPS, + MBL_MW_SENSOR_FUSION_GYRO_RANGE_500DPS, + MBL_MW_SENSOR_FUSION_GYRO_RANGE_250DPS +} MblMwSensorFusionGyroRange; + +/** + * Data computed by the algorithm + */ +typedef enum { + MBL_MW_SENSOR_FUSION_DATA_CORRECTED_ACC = 0, + MBL_MW_SENSOR_FUSION_DATA_CORRECTED_GYRO, + MBL_MW_SENSOR_FUSION_DATA_CORRECTED_MAG, + MBL_MW_SENSOR_FUSION_DATA_QUATERNION, + MBL_MW_SENSOR_FUSION_DATA_EULER_ANGLE, + MBL_MW_SENSOR_FUSION_DATA_GRAVITY_VECTOR, + MBL_MW_SENSOR_FUSION_DATA_LINEAR_ACC +} MblMwSensorFusionData; + +/** + * Container class holding the IMU calibration data + */ +typedef struct { + uint8_t acc[10]; + uint8_t gyro[10]; + uint8_t mag[10]; +} MblMwCalibrationData; + +/** + * Definition for callback functions that accept an MblMwMetaWearBoard and MblMwCalibrationData pointer + * @param context Additional parameters for the callback function + * @param board Calling object + * @param data Pointer to calibration data + */ +typedef void(*MblMwFnBoardPtrCalibDataPtr)(void *context, MblMwMetaWearBoard* board, const MblMwCalibrationData* data); + +/** + * Get the data signal object representing data from the sensor fusion algorithm + * The sensor fusion algo is a kalman filter that combines acc, gyro, and mag data into outputs such as correct acceleration, euler angles or quaternions + * @param board Calling object + * @param data Desired sensor fusion data + * @return Data signal object + * Return type can be MblMwCorrectedCartesianFloat, MblMwQuaternion, MblMwEulerAngl, MblMwCartesianFloat + */ +METAWEAR_API MblMwDataSignal* mbl_mw_sensor_fusion_get_data_signal(const MblMwMetaWearBoard* board, MblMwSensorFusionData data); +/** + * Get the data signal object representing thecalibration state. + * This signal can only be used while the sensor fusion algorithm is running + * @param board Calling object + * @return Data signal object + */ +METAWEAR_API MblMwDataSignal* mbl_mw_sensor_fusion_calibration_state_data_signal(const MblMwMetaWearBoard* board); +/** + * Set the operation mode + * See MblMwSensorFusionMode for allowed values + * @param board Calling object + * @param mode New operation mode + */ +METAWEAR_API void mbl_mw_sensor_fusion_set_mode(MblMwMetaWearBoard* board, MblMwSensorFusionMode mode); +/** + * Set the accelerometer data range + * Sets the range of the acc in Gs, see MblMwSensorFusionAccRange for allowed values + * @param board Calling object + * @param range New data range of the accelerometer + */ +METAWEAR_API void mbl_mw_sensor_fusion_set_acc_range(MblMwMetaWearBoard* board, MblMwSensorFusionAccRange range); +/** + * Set the gyroscope data range + * Sets the range of the gyro in DPS, see MblMwSensorFusionGyroRange for allowed values + * @param board Calling object + * @param range New data range of the gyroscope + */ +METAWEAR_API void mbl_mw_sensor_fusion_set_gyro_range(MblMwMetaWearBoard* board, MblMwSensorFusionGyroRange range); +/** + * Reset the default orientation of the board. + * Works while sensor fusion is running or off. Works for NDOF and IMUPLUS only. + * @param board Calling object + */ +METAWEAR_API void mbl_mw_sensor_fusion_reset_orientation(MblMwMetaWearBoard* board); +/** + * Write the module configuration to the board + * Applies the MODE and RANGE values set in set_*(). + * @param board Calling object + */ +METAWEAR_API void mbl_mw_sensor_fusion_write_config(MblMwMetaWearBoard* board); +/** + * Pulls the current sensor fusion configuration from the board + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param completed Callback function that is executed when the task is finished + */ +METAWEAR_API void mbl_mw_sensor_fusion_read_config(const MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrInt completed); +/** + * Retrieve IMU calibration data; free the memory allocated for the MblMwCalibrationData pointer with mbl_mw_memory_free. + * Only call this function when the calibration state of the IMUs is at high accuracy. + * This function can only be used with firmware v1.4.3+. + * @param board Calling object + * @param context Pointer to additional data for the callback function + * @param completed Callback function that is executed when the task is finished + */ +METAWEAR_API void mbl_mw_sensor_fusion_read_calibration_data(MblMwMetaWearBoard* board, void *context, MblMwFnBoardPtrCalibDataPtr completed); +/** + * Write IMU calibration data. The data will be reloaded everytime the mode changes. + * This function can only be used with firmware v1.4.3+ + * @param board Calling object + * @param data Calibration data to load + */ +METAWEAR_API void mbl_mw_sensor_fusion_write_calibration_data(const MblMwMetaWearBoard* board, const MblMwCalibrationData* data); +/** + * Set a data enable bit + * Turns on the Kalman filter (sensor fusion) + * @param board Calling object + * @param data Sensor fuson data to enable + */ +METAWEAR_API void mbl_mw_sensor_fusion_enable_data(MblMwMetaWearBoard* board, MblMwSensorFusionData data); +/** + * Clear all data enable bits + * Turns off the Kalman filter (sensor fusion) + * @param board Calling object + */ +METAWEAR_API void mbl_mw_sensor_fusion_clear_enabled_mask(MblMwMetaWearBoard* board); +/** + * Start sensor fusion + * The board will start gathering data from the gyroscope, accelerometer, and gyroscope and run the sensor fusion + * @param board Calling object + */ +METAWEAR_API void mbl_mw_sensor_fusion_start(const MblMwMetaWearBoard* board); +/** + * Stop sensor fusion + * The board will stop gathering data from the gyroscope, accelerometer, and gyroscope and stop the sensor fusion + * @param board Calling object + */ +METAWEAR_API void mbl_mw_sensor_fusion_stop(const MblMwMetaWearBoard* board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/spi.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/spi.h new file mode 100644 index 0000000..6537423 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/spi.h @@ -0,0 +1,72 @@ +/** + * @copyright MbientLab License (LICENSE.md) + * @file spi.h + * @brief Communicates with sensors on the SPI bus + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Available SPI clock frequencies + */ +typedef enum { + MBL_MW_SPI_FREQUENCY_125KHz = 0, + MBL_MW_SPI_FREQUENCY_250KHz, + MBL_MW_SPI_FREQUENCY_500KHz, + MBL_MW_SPI_FREQUENCY_1MHz, + MBL_MW_SPI_FREQUENCY_2MHz, + MBL_MW_SPI_FREQUENCY_4MHz, + MBL_MW_SPI_FREQUENCY_8MHz +} MblMwSpiFrequency; + +/** + * Available SPI modes, see SPI Wiki page + * for further details + */ +typedef enum { + MBL_MW_SPI_MODE_0= 0, ///< clock polarity 0, clock phase 0 + MBL_MW_SPI_MODE_1, ///< clock polarity 0, clock phase 1 + MBL_MW_SPI_MODE_2, ///< clock polarity 1, clock phase 0 + MBL_MW_SPI_MODE_3 ///< clock polarity 1, clock phase 1 +} MblMwSpiMode; + +/** + * Parameters required for an SPI operation + */ +typedef struct { + MblMwSpiMode mode; ///< spi mode + MblMwSpiFrequency frequency; ///< spi frequency + uint8_t *data; ///< Data to write through the bus, if set with a read, will write the data before performing the read + uint8_t data_length; ///< Length of the data array + uint8_t slave_select_pin; ///< pin for slave select + uint8_t clock_pin; ///< pin for spi clock + uint8_t mosi_pin; ///< pin for master out, slave in data + uint8_t miso_pin; ///< pin for master in, slave out data + uint8_t lsb_first; ///< Set to 0 if MSB should be sent first, non-zero to send LSB first + uint8_t use_nrf_pins; ///< Set to 0 to use MetaWear GPIO pin mapping, non-zero to use nRF pin mapping +} MblMwSpiParameters; + +/** + * Retrieves the data signal representing spi data. + * The data signal is identified by the id value and if the id is not present, a new data signal will be created using the length parameter. + * @param board Board to communicate with + * @param length Number of bytes to read + * @param id Numerical id identifying the data + * @return Pointer to the spi data signal + */ +METAWEAR_API MblMwDataSignal* mbl_mw_spi_get_data_signal(MblMwMetaWearBoard* board, uint8_t length, uint8_t id); +/** + * Writes data via the spi bus + * @param board Board to communicate with + * @param parameters Parameters configuring the read + */ +METAWEAR_API void mbl_mw_spi_write(const MblMwMetaWearBoard* board, const MblMwSpiParameters* parameters); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/switch.h b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/switch.h new file mode 100644 index 0000000..651290e --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/switch.h @@ -0,0 +1,25 @@ +/** + * @copyright MbientLab License + * @file switch.h + * @brief Push button switch + */ +#pragma once + +#include "sensor_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Retrieves the data signal representing switch state data + * The switch is either pushed (1) or not pushed (0) + * @param board Pointer to the board to retrieve the signal from + * @return Pointer to the switch data signal + * UINT32 is return signal data type + */ +METAWEAR_API MblMwDataSignal* mbl_mw_switch_get_state_data_signal(const MblMwMetaWearBoard *board); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/module.modulemap b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/module.modulemap new file mode 100644 index 0000000..d033b29 --- /dev/null +++ b/Pods/MetaWear/MetaWear/MetaWear-SDK-Cpp/src/module.modulemap @@ -0,0 +1,70 @@ +module MetaWearCpp [extern_c] { + header "metawear/core/metawearboard.h" + header "metawear/core/debug.h" + header "metawear/core/logging_fwd.h" + header "metawear/core/status.h" + header "metawear/core/event_fwd.h" + header "metawear/core/settings.h" + header "metawear/core/event.h" + header "metawear/core/types.h" + header "metawear/core/data.h" + header "metawear/core/timer_fwd.h" + header "metawear/core/macro.h" + header "metawear/core/datasignal_fwd.h" + header "metawear/core/logging.h" + header "metawear/core/timer.h" + header "metawear/core/metawearboard_fwd.h" + header "metawear/core/model.h" + header "metawear/core/datasignal.h" + header "metawear/core/module.h" + header "metawear/core/anonymous_datasignal.h" + header "metawear/core/metawearboard.h" + header "metawear/core/anonymous_datasignal_fwd.h" + header "metawear/processor/dataprocessor.h" + header "metawear/processor/passthrough.h" + header "metawear/processor/counter.h" + header "metawear/processor/packer.h" + header "metawear/processor/rms.h" + header "metawear/processor/math.h" + header "metawear/processor/delta.h" + header "metawear/processor/processor_common.h" + header "metawear/processor/dataprocessor_fwd.h" + header "metawear/processor/threshold.h" + header "metawear/processor/buffer.h" + header "metawear/processor/accumulator.h" + header "metawear/processor/time.h" + header "metawear/processor/comparator.h" + header "metawear/processor/pulse.h" + header "metawear/processor/average.h" + header "metawear/processor/sample.h" + header "metawear/processor/accounter.h" + header "metawear/processor/rss.h" + header "metawear/processor/fuser.h" + header "metawear/platform/btle_connection.h" + header "metawear/platform/dllmarker.h" + header "metawear/platform/memory.h" + header "metawear/sensor/accelerometer_mma8452q.h" + header "metawear/sensor/proximity_tsl2671.h" + header "metawear/sensor/accelerometer_bosch.h" + header "metawear/sensor/sensor_fusion.h" + header "metawear/sensor/accelerometer.h" + header "metawear/sensor/barometer_bosch.h" + header "metawear/sensor/gyro_bosch.h" + header "metawear/sensor/humidity_bme280.h" + header "metawear/sensor/colordetector_tcs34725.h" + header "metawear/sensor/multichanneltemperature.h" + header "metawear/sensor/sensor_common.h" + header "metawear/sensor/gpio.h" + header "metawear/sensor/magnetometer_bmm150.h" + header "metawear/sensor/spi.h" + header "metawear/sensor/ambientlight_ltr329.h" + header "metawear/sensor/switch.h" + header "metawear/sensor/i2c.h" + header "metawear/sensor/conductance.h" + header "metawear/peripheral/haptic.h" + header "metawear/peripheral/neopixel.h" + header "metawear/peripheral/led.h" + header "metawear/peripheral/peripheral_common.h" + header "metawear/peripheral/ibeacon.h" + export * +} diff --git a/Pods/MetaWear/README.md b/Pods/MetaWear/README.md new file mode 100644 index 0000000..2e8e231 --- /dev/null +++ b/Pods/MetaWear/README.md @@ -0,0 +1,158 @@ +# MetaWear SDK for iOS/macOS/tvOS/watchOS by MBIENTLAB + +[![Platforms](https://img.shields.io/cocoapods/p/MetaWear.svg?style=flat)](http://cocoapods.org/pods/MetaWear) +[![License](https://img.shields.io/cocoapods/l/MetaWear.svg?style=flat)](https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS/blob/master/LICENSE.md) +[![Version](https://img.shields.io/cocoapods/v/MetaWear.svg?style=flat)](http://cocoapods.org/pods/MetaWear) + +![alt tag](https://raw.githubusercontent.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS/master/Images/Metawear.png) + +SDK for creating MetaWear apps that run in the Apple ecosystem. + +This is a thin wrapper around the [MetaWear C++ API](https://github.com/mbientlab/MetaWear-SDK-Cpp) so you will find the C++ [documentation](https://mbientlab.com/cppdocs/latest/) and [API reference](https://mbientlab.com/docs/metawear/cpp/latest/globals.html) useful. + +Also, check out the starter [App](https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS/tree/master/StarterProject) and the very through example App [App](https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS/tree/master/ExampleApp) for sample code. + +### Overview + +[MetaWear](https://mbientlab.com) is a complete development and production platform for wearable and connected device applications. + +MetaWear features a number of sensors and peripherals all easily controllable over Bluetooth 4.0/5.0 Low Energy using this SDK, no firmware or hardware experience needed! + +The MetaWear hardware comes pre-loaded with a wirelessly upgradeable firmware, so it keeps getting more powerful over time. + +### Requirements +- [MetaWear board](https://mbientlab.com/store/) +- [Apple ID](https://appleid.apple.com/), you can now get started for free! Once you are ready to submit an App to the App Store, you need a paid [Apple Developer Account](https://developer.apple.com/programs/ios/). +- Device running iOS 14.0 or later with Bluetooth 4.0/5.0 (iOS 13+, XCODE12+, BLE5.0 recommended) + +> REQUIREMENT NOTES +The iOS simulator doesn’t support Bluetooth 4.0/5.0, so test apps must be run on a real iOS device which requires a developer account. Bluetooth 4.0 available on iPhone 4S+, iPad 3rd generation+, or iPod Touch 5th generation. + +*BLUETOOTH IS NOT SUPPORTED IN THE SIMULATOR* + +### License +See the [License](https://github.com/mbientlab/MetaWear-SDK-iOS-macOS-tvOS/blob/master/LICENSE.md) + +### Support +Reach out to the [community](https://mbientlab.com/community/) if you encounter any problems, or just want to chat :) + +## Getting Started + +### Pre-Installation + +#### Xcode +You need to be profficient with [Xcode](https://developer.apple.com/xcode/) development to use these APIs. + +#### Swift +Our APIs are written and supported in [Swift](https://developer.apple.com/swift/). + +#### CocoaPods +[CocoaPods](https://cocoapods.org/) is a dependency manager for Swift and Objective-C Cocoa projects. It has over 79 thousand libraries and is used in over 3 million apps. CocoaPods can help you scale your projects elegantly. + +CocoaPods is built with Ruby and is installable with the default Ruby available on macOS. We recommend you use the default ruby. + +Using the default Ruby install can require you to use sudo when installing gems. Further installation instructions are in the guides. + +```sh +sudo gem install cocoapods +``` +### Installation +[MetaWear](https://cocoapods.org/pods/MetaWear) is available through CocoaPods. To install it, simply add the following line to your Podfile: + +Then list the dependencies in a text file named Podfile in your Xcode project directory: + +```ruby +platform :ios, '14.0' +use_frameworks! +target 'MyApp' do + // LOCAL + pod "MetaWear", :subspecs => ['UI', 'AsyncUtils', 'DFU'] + // COCOA POD + pod "MetaWear" + // COCOA POD RELEASE SPECIFIC + pod "MetaWear", '~> '4.0.2' +end +``` +Tip: CocoaPods provides a pod init command to create a Podfile with smart defaults. You should use it. + +Now you can install the dependencies in your project: + +```sh +pod install +``` + +It might be good to update: + +```sh +pod update +``` + +Make sure to always open the Xcode workspace instead of the project file when building your project: + +```sh +open App.xcworkspace +``` +Now you can import your dependencies e.g.: + +```sh +#import MetaWear +``` + +### Usage +Require the metawear package + +```swift +import MetaWear +import MetaWearCpp +``` + +Call Swift APIs: +```swift +device.flashLED(color: .green, intensity: 1.0) +``` + +Or direct CPP SDK calls: +```swift +var pattern = MblMwLedPattern(high_intensity: 31, + low_intensity: 31, + rise_time_ms: 0, + high_time_ms: 2000, + fall_time_ms: 0, + pulse_duration_ms: 2000, + delay_time_ms: 0, + repeat_count: 0xFF) +mbl_mw_led_stop_and_clear(device.board) +mbl_mw_led_write_pattern(device.board, &pattern, color) +mbl_mw_led_play(device.board) +``` +Or a mix of both as you can see in the example below. + +### Example + +Here is a walkthrough to showcase a very basic connect and toggle LED operation. +```swift +MetaWearScanner.shared.startScan(allowDuplicates: true) { (device) in + // We found a MetaWear board, see if it is close + if device.rssi.intValue > -50 { + // Hooray! We found a MetaWear board, so stop scanning for more + MetaWearScanner.shared.stopScan() + // Connect to the board we found + device.connectAndSetup().continueWith { t in + if let error = t.error { + // Sorry we couldn't connect + print(error) + } else { + // Hooray! We connected to a MetaWear board, so flash its LED! + var pattern = MblMwLedPattern() + mbl_mw_led_load_preset_pattern(&pattern, MBL_MW_LED_PRESET_PULSE) + mbl_mw_led_stop_and_clear(device.board) + mbl_mw_led_write_pattern(device.board, &pattern, MBL_MW_LED_COLOR_GREEN) + mbl_mw_led_play(device.board) + } + } + } +} +``` + +### Tutorials +Tutorials can be found [here](https://mbientlab.com/tutorials/). diff --git a/Pods/PRTween/LICENSE b/Pods/PRTween/LICENSE new file mode 100644 index 0000000..4acb3aa --- /dev/null +++ b/Pods/PRTween/LICENSE @@ -0,0 +1,8 @@ +Copyright (c) 2011, Dominik Hofmann +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Pods/PRTween/README.md b/Pods/PRTween/README.md new file mode 100644 index 0000000..521e9c2 --- /dev/null +++ b/Pods/PRTween/README.md @@ -0,0 +1,307 @@ +PRTween +=== + +PRTween is a lightweight tweening library built for iOS. While Apple has done an incredible job with UIView Animations and Core Animation, there are sometimes cases that are difficult to get around. PRTween is a great alternative if you'd like to: + +* Animate a property Core Animation won't allow you to +* Ensure that `[someView layoutSubviews]` is respected during an animation +* Tween arbitrary numerical values, such as sound volume, scroll position, a counter, or many others +* Define your timing curve as a function rather than a bezier with control points + +PRTween aims to be as simple as possible without sacrificing flexibility. In many cases, an animation may be as simple as: + +```objective-c +[PRTween tween:someView property:@"alpha" from:1 to:0 duration:3]; +``` + +In order to promote simplicity, PRTween can be used as a drop-in replacement for most animations in your app. This means that in the case displayed above, the end result is identical to writing a UIView animation yourself. + +Status +=== + +So alpha. Seriously. + +Installation +=== + +Simply grab the PRTween and PRTweenTimingFunction files from /lib/ and get them into your project. + +Usage +=== + +At its core, PRTween is broken into two components. + +A **period** is a representation of three points in time (beginning, current, and end) for a particular value that you plan on tweening. For example, suppose that you are tweening a value from 100 to 200 over the course of 3 seconds. You can create an object to represent that period like this: + +```objective-c +PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:100 endValue:200 duration:3]; +``` + +The second component that makes up PRTween is an **operation**. An operation contains logistic information about how a period should play out, as well as what should happen while it does. You can think of a period as an abstract representation of work that should be carried out, and an operation as the worker who decides *how* it gets carried out. An operation might look like this: + +```objective-c +PRTweenOperation *operation = [[PRTweenOperation new] autorelease]; +operation.period = period; +operation.target = self; +operation.timingFunction = &PRTweenTimingFunctionLinear; +operation.updateSelector = @selector(update:) +``` + +The code above creates a new operation that carries out a tween over the period we defined earlier. Additionally, you've told the operation to call the `update:` selector on `self` every time the value is adjusted. `update:` might look like this: + +```objective-c +- (void)update:(PRTweenPeriod*)period { + NSLog(@"%f", period.tweenedValue); +} +``` + +Finally, you will need to add the operation to the queue. + +```objective-c +[[PRTween sharedInstance] addTweenOperation:operation] +``` + +As soon as you've done this and run your code, you should be able to see a console trace of a value moving from 100 to 200 over the course of 3 seconds. If you wanted to apply this to an object on screen, it could be as simple as changing `update:` to the following: + +```objective-c +// will animate the Y offset of testView from 100 to 200 over the course of 3 seconds +- (void)update:(PRTweenPeriod*)period { + testView.frame = CGRectMake(0, period.tweenedValue, 100, 100); +} +``` + +Timing Functions +=== + +Timing functions are a key feature of PRTween, and allow you to modify how an operation interprets a period. For example, try changing `operation.timingFunction` from `&PRTweenTimingFunctionLinear` to `&PRTweenTimingFunctionBounceOut` and running your code again. You should see a similar animation play out, but this time a bounce will be added to the end of it. PRTween comes bundled with a number of timing functions for your convenience: + +* PRTweenTimingFunctionLinear +* PRTweenTimingFunctionBack*[In / Out / InOut]* +* PRTweenTimingFunctionBounce*[In / Out / InOut]* +* PRTweenTimingFunctionCirc*[In / Out / InOut]* +* PRTweenTimingFunctionCubic*[In / Out / InOut]* +* PRTweenTimingFunctionElastic*[In / Out / InOut]* +* PRTweenTimingFunctionExpo*[In / Out / InOut]* +* PRTweenTimingFunctionQuad*[In / Out / InOut]* +* PRTweenTimingFunctionQuart*[In / Out / InOut]* +* PRTweenTimingFunctionQuint*[In / Out / InOut]* +* PRTweenTimingFunctionSine*[In / Out / InOut]* + +You should take some time to experiment with PRTween's timing functions in your applications to see which ones you like best. + +Whenever `timingFunction` is omitted from a tween in PRTween, the default timing function is used. This is accessible through the `defaultTimingFunction` property on `PRTween`, although you will generally access it through `[PRTween sharedInstance].defaultTimingFunction`. + +Custom Functions +--- + +One of the most powerful capabilities of PRTween is the ability to write your own timing functions. In lieu of documentation at this time, have a look through PRTweenTimingFunctions.m for example timing functions. + +Shorthand +=== + +The code in the examples above is far from unwieldy, but it could still stand to be simplified. For the most common cases, PRTween offers **shorthand** functionality to reduce the amount of code that needs to be written. + +For example, a simple alpha tween may be written concisely as: + +```objective-c +[PRTween tween:testView property:@"alpha" from:1 to:0 duration:3]; +``` + +You can also directly tween values that might not be properties. Suppose you're developing a game that has a scrollPosition `CGFloat`: + +```objective-c +[PRTween tween:&scrollPosition from:0 to:20 duration:3]; +``` + +PRTween currently supports the following base shorthands: + +```objective-c +// for properties on objects +[PRTween tween:property:from:to:duration:timingFunction:target:completeSelector:] +[PRTween tween:property:from:to:duration:] + +// for values +[PRTween tween:from:to:duration:timingFunction:target:completeSelector:] +[PRTween tween:from:to:duration:] +``` + +PRTween also supports shorthands for blocks and lerps, explained below. + +Fallbacks +=== + +In many cases, the UIView or Core Animation functionality bundled with iOS will do the job just fine. PRTween attempts to be intelligent about this, and will use a **fallback** for any property that can be animated by UIView or Core Animation. + +For example, writing this code in PRTween: + +```objective-c +[PRTween tween:someView property:@"alpha" from:1 to:0 duration:3]; +``` + +Is identical to writing this code without PRTween: + +```objective-c +someView.alpha = 1; +[UIView beginAnimations:nil context:NULL]; +[UIView setAnimationDuration:3]; +someView.alpha = 0; +[UIView commitAnimations]; +``` + +Fallbacks can be disabled on a **case-by-case** basis with the following syntax: + +```objective-c +[PRTween tween:someView property:@"alpha" from:1 to:0 duration:2].override = YES; +``` + +Or **globally**: + +```objective-c +[PRTween sharedInstance].useBuiltInAnimationsWhenPossible = NO; +``` + +The following _UIView_ properties are eligible for UIView fallbacks: + +* frame +* bounds +* center +* transform +* alpha +* contentStretch + +The following _CALayer_ properties are eligible Core Animation fallbacks: + +* bounds +* position +* zPosition +* anchorPoint +* anchorPointZ +* frame +* contentsRect +* contentsScale +* contentsCenter +* cornerRadius +* borderWidth +* opacity +* shadowOpacity +* shadowOffset +* shadowRadius + +Support for CGColor, CGPath, and CATransform3D properties for fallbacks is forthcoming. + +Note the **using an unsupported timing function will disqualify an animation** that was eligible for fallbacks. Only the built-in curves bundled with iOS are supported for fallbacks. They can be accessed through the following: + +* PRTweenTimingFunctionCALinear +* PRTweenTimingFunctionCAEaseIn +* PRTweenTimingFunctionCAEaseOut +* PRTweenTimingFunctionCAEaseInOut +* PRTweenTimingFunctionCADefault +* PRTweenTimingFunctionUIViewLinear +* PRTweenTimingFunctionUIViewEaseIn +* PRTweenTimingFunctionUIViewEaseOut +* PRTweenTimingFunctionUIViewEaseInOut + +Blocks +=== + +If you are targeting iOS 4 or greater, you can take advantage of blocks when using PRTween. Blocks are particularly useful for keeping all your code in one place. For example, we could remove the `update:` method from the example above, and replace it with the following line in our declaration of `operation`: + +```objective-c +operation.updateBlock = ^(PRTweenPeriod *period) { + testView.frame = CGRectMake(0, period.tweenedValue, 100, 100); +}; +``` + +You can also use blocks to execute code after the animation is complete. + +```objective-c +operation.completeBlock = ^{ + NSLog("@All done!") +}; +``` + +Blocks are also available on shorthands: + +```objective-c +// for properties on objects +[PRTween tween:property:from:to:duration:timingFunction:updateBlock:completeBlock] + +// for values +[PRTween tween:from:to:duration:timingFunction:updateBlock:completeBlock] +``` + +Lerps +=== + +Sometimes you will find it necessary to animate a complex value, such as a `CGPoint`. Although you could write two tweens for the `x` and `y` fields, it is much simpler to use linear interpolation, or **lerps**. In PRTween, a lerp is differentiated from a normal tween by using a `PRTweenLerpPeriod`. For example, we might change our declaration of `period` above: + +```objective-c +PRTweenCGPointLerpPeriod *period = [PRTweenCGPointLerpPeriod periodWithStartCGPoint:CGPointMake(0, 0) endCGPoint:CGPointMake(100, 100) duration:2]; +``` + +PRTween currently has built-in lerps for `CGPoint` and `CGRect` and `CGSize` through `PRTweenCGPointLerpPeriod`, `PRTweenCGRectLerpPeriod` and `PRTweenCGSizeLerpPeriod`. Lerps are also available as shorthands: + +```objective-c +// for CGPoint +[PRTweenCGPointLerp lerp:property:from:to:duration:timingFunction:target:completeSelector:] +[PRTweenCGPointLerp lerp:property:from:to:duration:] + +// for CGSize +[PRTweenCGSizeLerp lerp:property:from:to:duration:timingFunction:target:completeSelector:] +[PRTweenCGSizeLerp lerp:property:from:to:duration:] + +// for CGRect +[PRTweenCGRectLerp lerp:property:from:to:duration:timingFunction:target:completeSelector:] +[PRTweenCGRectLerp lerp:property:from:to:duration:] + + +// blocks for iOS 4 or greater +[PRTweenCGPointLerp lerp:property:from:to:duration:timingFunction:target:updateBlock:completeBlock:] +[PRTweenCGSizeLerp lerp:property:from:to:duration:timingFunction:target:updateBlock:completeBlock:] +[PRTweenCGRectLerp lerp:property:from:to:duration:timingFunction:target:updateBlock:completeBlock:] +``` + +Custom Lerps +--- + +One of the most powerful features of PRTween is its ability to use custom lerps. In general, classes that subclass `PRTweenLerpPeriod` and implement the `` protocol may be used as custom lerps. This allows us to tween any complex numerical value with ease. Documentation is forthcoming, but for now you can check the code behind `PRTweenCGPointLerpPeriod` for more details. + +Advanced +=== + +API docs are coming shortly. Until then, you are encouraged to dig through the code for details on advanced functionality. PRTween is very minimal, so you can probably figure everything out in an hour or two. + +Contributing +=== + +PRTween is incredibly young, so there aren't many rules right now. + +* Fork it +* Fix it or add it +* Add yourself to the contributor list +* Commit +* Send a pull request + +Contributors +--- + +* [Dominik Hofmann](https://github.com/dominikhofmann/) +* [Matt Herzog](https://github.com/mattherzog/) +* [Robert Brisita](https://github.com/transmitiveRB/) +* [Ludwig Schubert](https://github.com/ludwigschubert) + +License +=== +Surprise! It's a BSD license. + +
+Copyright (c) 2011, Dominik Hofmann
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ diff --git a/Pods/PRTween/lib/PRTween.h b/Pods/PRTween/lib/PRTween.h new file mode 100755 index 0000000..2f367ef --- /dev/null +++ b/Pods/PRTween/lib/PRTween.h @@ -0,0 +1,443 @@ +#import +#import "PRTweenTimingFunctions.h" + +typedef CGFloat(*PRTweenTimingFunction)(CGFloat, CGFloat, CGFloat, CGFloat); + +#if NS_BLOCKS_AVAILABLE +@class PRTweenPeriod; + +typedef void (^PRTweenUpdateBlock)(PRTweenPeriod *period); + +typedef void (^PRTweenCompleteBlock)(BOOL finished); + +#endif + +enum { + PRTweenHasTweenedValueObserver = 1 << 0, + PRTweenHasTweenedLerpObserver = 1 << 1, +}; +typedef NSUInteger PRTweenHasTweenedObserverOptions; + +@interface PRTweenPeriod : NSObject { + CGFloat duration; + CGFloat delay; + CGFloat startOffset; + CGFloat startValue; + CGFloat endValue; + CGFloat tweenedValue; +} + +@property(nonatomic) CGFloat startValue; +@property(nonatomic) CGFloat endValue; +@property(nonatomic) CGFloat tweenedValue; +@property(nonatomic) CGFloat duration; +@property(nonatomic) CGFloat delay; +@property(nonatomic) CGFloat startOffset; + ++ (id)periodWithStartValue:(CGFloat)aStartValue + endValue:(CGFloat)anEndValue + duration:(CGFloat)duration; + ++ (id)periodWithStartValue:(CGFloat)aStartValue + endValue:(CGFloat)anEndValue + duration:(CGFloat)duration + delay:(CGFloat)delay; + +@end + +@protocol PRTweenLerpPeriod + +- (NSValue *)tweenedValueForProgress:(CGFloat)progress; + +- (void)setProgress:(CGFloat)progress; + +@end + +@interface PRTweenLerpPeriod : PRTweenPeriod { + NSValue *startLerp; + NSValue *endLerp; + NSValue *tweenedLerp; +} + +@property(nonatomic, copy) NSValue *startLerp; +@property(nonatomic, copy) NSValue *endLerp; +@property(nonatomic, copy) NSValue *tweenedLerp; + ++ (id)periodWithStartValue:(NSValue *)aStartValue + endValue:(NSValue *)anEndValue + duration:(CGFloat)duration; + ++ (id)periodWithStartValue:(NSValue *)aStartValue + endValue:(NSValue *)anEndValue + duration:(CGFloat)duration + delay:(CGFloat)delay; +@end + +@interface PRTweenCGPointLerpPeriod : PRTweenLerpPeriod ++ (id)periodWithStartCGPoint:(CGPoint)aStartPoint + endCGPoint:(CGPoint)anEndPoint + duration:(CGFloat)duration; + +- (CGPoint)startCGPoint; + +- (CGPoint)tweenedCGPoint; + +- (CGPoint)endCGPoint; +@end + +@interface PRTweenCGRectLerpPeriod : PRTweenLerpPeriod ++ (id)periodWithStartCGRect:(CGRect)aStartRect + endCGRect:(CGRect)anEndRect + duration:(CGFloat)duration; + +- (CGRect)startCGRect; + +- (CGRect)tweenedCGRect; + +- (CGRect)endCGRect; +@end + +@interface PRTweenCGSizeLerpPeriod : PRTweenLerpPeriod ++ (id)periodWithStartCGSize:(CGSize)aStartSize + endCGSize:(CGSize)anEndSize + duration:(CGFloat)duration; + ++ (id)periodWithStartCGSize:(CGSize)aStartSize + endCGSize:(CGSize)anEndSize + duration:(CGFloat)duration + delay:(CGFloat)delay; + +- (CGSize)startCGSize; + +- (CGSize)tweenedCGSize; + +- (CGSize)endCGSize; +@end + +@interface PRTweenOperation : NSObject { + PRTweenPeriod *period; + NSObject *target; + SEL updateSelector; + SEL completeSelector; + PRTweenTimingFunction timingFunction; + + CGFloat *boundRef; + SEL boundGetter; + SEL boundSetter; + + BOOL override; + BOOL wasPreempted; + + PRTweenHasTweenedObserverOptions observers; + +#if NS_BLOCKS_AVAILABLE + PRTweenUpdateBlock updateBlock; + PRTweenCompleteBlock completeBlock; +#endif + +@private + BOOL canUseBuiltAnimation; +} + +@property(nonatomic, retain) PRTweenPeriod *period; +@property(nonatomic, retain) NSObject *target; +@property(nonatomic) SEL updateSelector; +@property(nonatomic) SEL completeSelector; +@property(nonatomic, assign) PRTweenTimingFunction timingFunction; + +#if NS_BLOCKS_AVAILABLE +@property(nonatomic, copy) PRTweenUpdateBlock updateBlock; +@property(nonatomic, copy) PRTweenCompleteBlock completeBlock; +#endif + +@property(nonatomic, assign) CGFloat *boundRef; +@property(nonatomic, retain) id boundObject; +@property(nonatomic) SEL boundGetter; +@property(nonatomic) SEL boundSetter; +@property(nonatomic) BOOL override; +@property(nonatomic) BOOL wasPreempted; + +@property(nonatomic) PRTweenHasTweenedObserverOptions observers; + +@end + +@interface PRTweenCGPointLerp : NSObject ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration; + +#if NS_BLOCKS_AVAILABLE + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + +#endif +@end + +@interface PRTweenCGRectLerp : NSObject ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration; + +#if NS_BLOCKS_AVAILABLE + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + +#endif +@end + +@interface PRTweenCGSizeLerp : NSObject ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration; + +#if NS_BLOCKS_AVAILABLE + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + +//+ (PRTweenOperation *)lerp:(id)object +// property:(NSString *)property +// from:(CGSize)from +// to:(CGSize)to +// duration:(CGFloat)duration +// delay:(CGFloat)delay +// timingFunction:(PRTweenTimingFunction)timingFunction +// updateBlock:(PRTweenUpdateBlock)updateBlock +// completeBlock:(PRTweenCompleteBlock)completeBlock; + +#endif +@end + +@interface PRTween : NSObject { + NSMutableArray *tweenOperations; + NSMutableArray *expiredTweenOperations; + NSTimer *timer; + CGFloat timeOffset; + + PRTweenTimingFunction defaultTimingFunction; + BOOL useBuiltInAnimationsWhenPossible; +} + +@property(nonatomic, readonly) CGFloat timeOffset; +@property(nonatomic, assign) PRTweenTimingFunction defaultTimingFunction; +@property(nonatomic, assign) BOOL useBuiltInAnimationsWhenPossible; + ++ (PRTween *)sharedInstance; + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + period:(PRTweenLerpPeriod *)period + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + +- (PRTweenOperation *)addTweenOperation:(PRTweenOperation *)operation; + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + target:(NSObject *)target + selector:(SEL)selector; + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + target:(NSObject *)target + selector:(SEL)selector + timingFunction:(PRTweenTimingFunction)timingFunction; + +- (void)removeTweenOperation:(PRTweenOperation *)tweenOperation; + +- (void)removeAllTweenOperations; + +#if NS_BLOCKS_AVAILABLE + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + period:(PRTweenLerpPeriod *)period + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + updateBlock:(PRTweenUpdateBlock)updateBlock + completionBlock:(PRTweenCompleteBlock)completeBlock; + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + updateBlock:(PRTweenUpdateBlock)updateBlock + completionBlock:(PRTweenCompleteBlock)completionBlock + timingFunction:(PRTweenTimingFunction)timingFunction; + +#endif + +@end diff --git a/Pods/PRTween/lib/PRTween.m b/Pods/PRTween/lib/PRTween.m new file mode 100755 index 0000000..b654374 --- /dev/null +++ b/Pods/PRTween/lib/PRTween.m @@ -0,0 +1,1175 @@ + +#import "PRTween.h" + +#define kPRTweenFramerate 1.0/60 + +@implementation PRTweenPeriod +@synthesize startValue; +@synthesize endValue; +@synthesize tweenedValue; +@synthesize duration; +@synthesize delay; +@synthesize startOffset; + ++ (id)periodWithStartValue:(CGFloat)aStartValue + endValue:(CGFloat)anEndValue + duration:(CGFloat)duration { + + PRTweenPeriod *period = [PRTweenPeriod new]; + + period.startValue = period.tweenedValue = aStartValue; + period.endValue = anEndValue; + period.duration = duration; + period.startOffset = [[PRTween sharedInstance] timeOffset]; + + return period; +} + ++ (id)periodWithStartValue:(CGFloat)aStartValue + endValue:(CGFloat)anEndValue + duration:(CGFloat)duration + delay:(CGFloat)delay { + + PRTweenPeriod *period = [PRTweenPeriod new]; + + period.startValue = period.tweenedValue = aStartValue; + period.endValue = anEndValue; + period.duration = duration; + period.delay = delay; + period.startOffset = [[PRTween sharedInstance] timeOffset]; + + return period; +} + +@end + +@implementation PRTweenLerpPeriod +@synthesize startLerp; +@synthesize endLerp; +@synthesize tweenedLerp; + ++ (id)periodWithStartValue:(NSValue *)aStartValue + endValue:(NSValue *)anEndValue + duration:(CGFloat)duration { + + PRTweenLerpPeriod *period = [[self class] new]; + period.startLerp = aStartValue; + period.tweenedLerp = aStartValue; + period.endLerp = anEndValue; + period.duration = duration; + period.startOffset = [[PRTween sharedInstance] timeOffset]; + + return period; +} + ++ (id)periodWithStartValue:(NSValue *)aStartValue + endValue:(NSValue *)anEndValue + duration:(CGFloat)duration + delay:(CGFloat)delay { + + PRTweenLerpPeriod *period = [[self class] new]; + period.startLerp = aStartValue; + period.tweenedLerp = aStartValue; + period.endLerp = anEndValue; + period.duration = duration; + period.delay = delay; + period.startOffset = [[PRTween sharedInstance] timeOffset]; + + return period; +} + +@end + +@implementation PRTweenCGPointLerpPeriod + ++ (id)periodWithStartCGPoint:(CGPoint)aStartPoint + endCGPoint:(CGPoint)anEndPoint + duration:(CGFloat)duration { + + return [PRTweenCGPointLerpPeriod periodWithStartValue:[NSValue valueWithCGPoint:aStartPoint] endValue:[NSValue valueWithCGPoint:anEndPoint] duration:duration]; +} + +- (CGPoint)startCGPoint { + return [self.startLerp CGPointValue]; +} + +- (CGPoint)tweenedCGPoint { + return [self.tweenedLerp CGPointValue]; +} + +- (CGPoint)endCGPoint { + return [self.endLerp CGPointValue]; +} + +- (NSValue *)tweenedValueForProgress:(CGFloat)progress { + + CGPoint startPoint = self.startCGPoint; + CGPoint endPoint = self.endCGPoint; + CGPoint distance = CGPointMake(endPoint.x - startPoint.x, endPoint.y - startPoint.y); + CGPoint tweenedPoint = CGPointMake(startPoint.x + distance.x * progress, startPoint.y + distance.y * progress); + + return [NSValue valueWithCGPoint:tweenedPoint]; + +} + +- (void)setProgress:(CGFloat)progress { + self.tweenedLerp = [self tweenedValueForProgress:progress]; +} + +@end + +@implementation PRTweenCGRectLerpPeriod + ++ (id)periodWithStartCGRect:(CGRect)aStartRect + endCGRect:(CGRect)anEndRect + duration:(CGFloat)duration { + + return [PRTweenCGRectLerpPeriod periodWithStartValue:[NSValue valueWithCGRect:aStartRect] endValue:[NSValue valueWithCGRect:anEndRect] duration:duration]; +} + +- (CGRect)startCGRect { + return [self.startLerp CGRectValue]; +} + +- (CGRect)tweenedCGRect { + return [self.tweenedLerp CGRectValue]; +} + +- (CGRect)endCGRect { + return [self.endLerp CGRectValue]; +} + +- (NSValue *)tweenedValueForProgress:(CGFloat)progress { + + CGRect startRect = self.startCGRect; + CGRect endRect = self.endCGRect; + CGRect distance = CGRectMake(endRect.origin.x - startRect.origin.x, endRect.origin.y - startRect.origin.y, endRect.size.width - startRect.size.width, endRect.size.height - startRect.size.height); + CGRect tweenedRect = CGRectMake(startRect.origin.x + distance.origin.x * progress, startRect.origin.y + distance.origin.y * progress, startRect.size.width + distance.size.width * progress, startRect.size.height + distance.size.height * progress); + + return [NSValue valueWithCGRect:tweenedRect]; + +} + +- (void)setProgress:(CGFloat)progress { + self.tweenedLerp = [self tweenedValueForProgress:progress]; +} + +@end + +@implementation PRTweenCGSizeLerpPeriod + ++ (id)periodWithStartCGSize:(CGSize)aStartSize + endCGSize:(CGSize)anEndSize + duration:(CGFloat)duration { + + return [PRTweenCGRectLerpPeriod periodWithStartValue:[NSValue valueWithCGSize:aStartSize] endValue:[NSValue valueWithCGSize:anEndSize] duration:duration]; +} + ++ (id)periodWithStartCGSize:(CGSize)aStartSize + endCGSize:(CGSize)anEndSize + duration:(CGFloat)duration + delay:(CGFloat)delay { + + return [PRTweenCGRectLerpPeriod periodWithStartValue:[NSValue valueWithCGSize:aStartSize] endValue:[NSValue valueWithCGSize:anEndSize] duration:duration delay:delay]; +} + +- (CGSize)startCGSize { + return [self.startLerp CGSizeValue]; +} + +- (CGSize)tweenedCGSize { + return [self.tweenedLerp CGSizeValue]; +} + +- (CGSize)endCGSize { + return [self.endLerp CGSizeValue]; +} + +- (NSValue *)tweenedValueForProgress:(CGFloat)progress { + + CGSize startSize = self.startCGSize; + CGSize endSize = self.endCGSize; + CGSize distance = CGSizeMake(endSize.width - startSize.width, endSize.height - startSize.height); + CGSize tweenedSize = CGSizeMake(startSize.width + distance.width * progress, startSize.height + distance.height * progress); + return [NSValue valueWithCGSize:tweenedSize]; + +} + +- (void)setProgress:(CGFloat)progress { + self.tweenedLerp = [self tweenedValueForProgress:progress]; +} + +@end + +@interface PRTweenOperation () +@property(nonatomic) BOOL canUseBuiltAnimation; +@end + +@implementation PRTweenOperation +@synthesize period; +@synthesize target; +@synthesize updateSelector; +@synthesize completeSelector; +@synthesize timingFunction; +@synthesize boundRef; +@synthesize boundObject; +@synthesize boundGetter; +@synthesize boundSetter; +@synthesize canUseBuiltAnimation; +@synthesize override; +@synthesize wasPreempted; +@synthesize observers; + +#if NS_BLOCKS_AVAILABLE +@synthesize updateBlock; +@synthesize completeBlock; +#endif + +@end + +@implementation PRTweenCGPointLerp + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + return [PRTween lerp:object + property:property + period:[PRTweenCGPointLerpPeriod + periodWithStartCGPoint:from + endCGPoint:to + duration:duration] + timingFunction:timingFunction + target:target + completeSelector:selector]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenCGPointLerpPeriod *period = [PRTweenCGPointLerpPeriod periodWithStartCGPoint:from endCGPoint:to duration:duration]; + period.delay = delay; + + return [PRTween lerp:object + property:property + period:period + timingFunction:timingFunction + target:target + completeSelector:selector]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration { + + return [PRTweenCGPointLerp + lerp:object + property:property + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; +} + +#if NS_BLOCKS_AVAILABLE + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + return [PRTween lerp:object + property:property + period:[PRTweenCGPointLerpPeriod + periodWithStartCGPoint:from + endCGPoint:to + duration:duration] + timingFunction:timingFunction + updateBlock:updateBlock + completeBlock:completeBlock]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenCGPointLerpPeriod *period = [PRTweenCGPointLerpPeriod periodWithStartCGPoint:from endCGPoint:to duration:duration]; + [period setDelay:delay]; + + return [PRTween lerp:object property:property period:period timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; +} + +#endif + +@end + +@implementation PRTweenCGRectLerp + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + return [PRTween lerp:object + property:property + period:[PRTweenCGRectLerpPeriod + periodWithStartCGRect:from + endCGRect:to + duration:duration] + timingFunction:timingFunction + target:target + completeSelector:selector]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenCGRectLerpPeriod *period = [PRTweenCGRectLerpPeriod periodWithStartCGRect:from + endCGRect:to + duration:duration]; + period.delay = delay; + return [PRTween lerp:object + property:property + period:period + timingFunction:timingFunction + target:target + completeSelector:selector]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration { + + return [PRTweenCGRectLerp lerp:object + property:property + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; +} + +#if NS_BLOCKS_AVAILABLE + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + return [PRTween lerp:object property:property period:[PRTweenCGRectLerpPeriod periodWithStartCGRect:from endCGRect:to duration:duration] timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenCGRectLerpPeriod *period = [PRTweenCGRectLerpPeriod periodWithStartCGRect:from endCGRect:to duration:duration]; + [period setDelay:delay]; + + return [PRTween lerp:object property:property period:period timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; +} + +#endif + +@end + +@implementation PRTweenCGSizeLerp + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + return [PRTween lerp:object + property:property + period:[PRTweenCGSizeLerpPeriod + periodWithStartCGSize:from + endCGSize:to + duration:duration] + timingFunction:timingFunction + target:target + completeSelector:selector]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenCGPointLerpPeriod *period = [PRTweenCGSizeLerpPeriod periodWithStartCGSize:from + endCGSize:to + duration:duration]; + period.delay = delay; + return [PRTween lerp:object + property:property + period:period + timingFunction:timingFunction + target:target + completeSelector:selector]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration { + + return [PRTweenCGSizeLerp lerp:object + property:property + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; +} + +#if NS_BLOCKS_AVAILABLE + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + return [PRTween lerp:object + property:property + period:[PRTweenCGSizeLerpPeriod + periodWithStartCGSize:from + endCGSize:to + duration:duration] + timingFunction:timingFunction + updateBlock:updateBlock + completeBlock:completeBlock]; +} + +#endif + +@end + +@interface PRTween () ++ (SEL)setterFromProperty:(NSString *)property; + +- (void)update; +@end + +static PRTween *instance = nil; +static NSArray *animationSelectorsForCoreAnimation = nil; +static NSArray *animationSelectorsForUIView = nil; + +@implementation PRTween +@synthesize timeOffset; +@synthesize defaultTimingFunction; +@synthesize useBuiltInAnimationsWhenPossible; + ++ (PRTween *)sharedInstance { + if (instance == nil) { + instance = [[PRTween alloc] init]; + instance.useBuiltInAnimationsWhenPossible = YES; + } + return instance; +} + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.target = target; + operation.completeSelector = selector; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; + return operation; + +} + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.target = target; + operation.completeSelector = selector; + operation.boundRef = ref; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + +} + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration + delay:delay]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.target = target; + operation.completeSelector = selector; + operation.boundRef = ref; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + +} + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration { + + return [PRTween tween:object + property:property + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; +} + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration { + + return [PRTween tween:ref + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + period:(PRTweenLerpPeriod *)period + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + //PRTweenPeriod *period = [PRTweenLerpPeriod periodWithStartValue:from endValue:to duration:duration]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.target = target; + operation.completeSelector = selector; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedLerp" observerOptions:PRTweenHasTweenedLerpObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + +} + +#if NS_BLOCKS_AVAILABLE + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; + return operation; + +} + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration + delay:delay]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; + return operation; + +} + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundRef = ref; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + +} + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration + delay:delay]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundRef = ref; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + period:(PRTweenLerpPeriod *)period + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + //PRTweenPeriod *period = [PRTweenLerpPeriod periodWithStartValue:from endValue:to duration:duration]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedLerp" observerOptions:PRTweenHasTweenedLerpObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + +} + +#endif + ++ (void)addObserver:(NSObject *)observer + forKeyPath:(NSString *)keyPath + observerOptions:(PRTweenHasTweenedObserverOptions)observerOptions + operation:(PRTweenOperation *)operation { + + [operation addObserver:observer forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; + operation.observers = operation.observers | observerOptions; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + + PRTweenOperation *operation = (PRTweenOperation *) object; + + if ([operation.period isKindOfClass:[PRTweenLerpPeriod class]]) { + PRTweenLerpPeriod *lerpPeriod = (PRTweenLerpPeriod *) operation.period; + + NSUInteger bufferSize = 0; + NSGetSizeAndAlignment([lerpPeriod.tweenedLerp objCType], &bufferSize, NULL); + void *tweenedValue = malloc(bufferSize); + [lerpPeriod.tweenedLerp getValue:tweenedValue]; + + if (operation.boundObject && [operation.boundObject respondsToSelector:operation.boundGetter] && [operation.boundObject respondsToSelector:operation.boundSetter]) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[operation.boundObject class] + instanceMethodSignatureForSelector:operation.boundSetter]]; + [invocation setTarget:operation.boundObject]; + [invocation setSelector:operation.boundSetter]; + [invocation setArgument:tweenedValue atIndex:2]; + [invocation invoke]; + } + + free(tweenedValue); + + } else { + + CGFloat tweenedValue = operation.period.tweenedValue; + + if (operation.boundObject && [operation.boundObject respondsToSelector:operation.boundGetter] && [operation.boundObject respondsToSelector:operation.boundSetter]) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[operation.boundObject class] + instanceMethodSignatureForSelector:operation.boundSetter]]; + [invocation setTarget:operation.boundObject]; + [invocation setSelector:operation.boundSetter]; + [invocation setArgument:&tweenedValue atIndex:2]; + [invocation invoke]; + } else if (operation.boundRef) { + *operation.boundRef = tweenedValue; + } + + } + +} + +- (id)init { + self = [super init]; + if (self != nil) { + tweenOperations = [[NSMutableArray alloc] init]; + expiredTweenOperations = [[NSMutableArray alloc] init]; + timeOffset = 0; + if (timer == nil) { + timer = [NSTimer scheduledTimerWithTimeInterval:kPRTweenFramerate target:self selector:@selector(update) userInfo:nil repeats:YES]; + [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; + } + self.defaultTimingFunction = &PRTweenTimingFunctionQuadInOut; + } + return self; +} + +- (PRTweenOperation *)addTweenOperation:(PRTweenOperation *)operation { + + if (useBuiltInAnimationsWhenPossible && !operation.override) { + + if (animationSelectorsForCoreAnimation == nil) { + animationSelectorsForCoreAnimation = [[NSArray alloc] initWithObjects: + @"setBounds:", // CGRect + @"setPosition:", // CGPoint + @"setZPosition:", // CGFloat + @"setAnchorPoint:", // CGPoint + @"setAnchorPointZ:", // CGFloat + //@"setTransform:", // CATransform3D + //@"setSublayerTransform:", // CATransform3D + @"setFrame:", // CGRect + @"setContentsRect" // CGRect + @"setContentsScale:", // CGFloat + @"setContentsCenter:", // CGPoint + //@"setBackgroundColor:", // CGColorRef + @"setCornerRadius:", // CGFloat + @"setBorderWidth:", // CGFloat + @"setOpacity:", // CGFloat + //@"setShadowColor:", // CGColorRef + @"setShadowOpacity:", // CGFloat + @"setShadowOffset:", // CGSize + @"setShadowRadius:", // CGFloat + //@"setShadowPath:", + nil]; + } + + if (animationSelectorsForUIView == nil) { + animationSelectorsForUIView = [[NSArray alloc] initWithObjects: + @"setFrame:", // CGRect + @"setBounds:", // CGRect + @"setCenter:", // CGPoint + @"setTransform:", // CGAffineTransform + @"setAlpha:", // CGFloat + //@"setBackgroundColor:", // UIColor + @"setContentStretch:", // CGRect + nil]; + } + + if (operation.boundSetter && operation.boundObject && !(operation.timingFunction == &PRTweenTimingFunctionCADefault || + operation.timingFunction == &PRTweenTimingFunctionCAEaseIn || + operation.timingFunction == &PRTweenTimingFunctionCAEaseOut || + operation.timingFunction == &PRTweenTimingFunctionCAEaseInOut || + operation.timingFunction == &PRTweenTimingFunctionCALinear || + operation.timingFunction == &PRTweenTimingFunctionUIViewEaseIn || + operation.timingFunction == &PRTweenTimingFunctionUIViewEaseOut || + operation.timingFunction == &PRTweenTimingFunctionUIViewEaseInOut || + operation.timingFunction == &PRTweenTimingFunctionUIViewLinear || + operation.timingFunction == NULL)) { + goto complete; + } + + + if (operation.boundSetter && operation.boundObject && [operation.boundObject isKindOfClass:[CALayer class]]) { + for (NSString *selector in animationSelectorsForCoreAnimation) { + NSString *setter = NSStringFromSelector(operation.boundSetter); + if ([selector isEqualToString:setter]) { + NSLog(@"Using Core Animation for %@", NSStringFromSelector(operation.boundSetter)); + operation.canUseBuiltAnimation = YES; + + NSString *propertyUnformatted = [selector stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""]; + NSString *propertyFormatted = [[propertyUnformatted stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[propertyUnformatted substringToIndex:1] + lowercaseString]] substringToIndex:[propertyUnformatted length] - 1]; + //NSLog(@"%@", propertyFormatted); + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:propertyFormatted]; + animation.duration = operation.period.duration; + + if (![operation.period isKindOfClass:[PRTweenLerpPeriod class]] && ![operation.period conformsToProtocol:@protocol(PRTweenLerpPeriod)]) { + animation.fromValue = [NSNumber numberWithFloat:operation.period.startValue]; + animation.toValue = [NSNumber numberWithFloat:operation.period.endValue]; + } else { + PRTweenLerpPeriod *period = (PRTweenLerpPeriod *) operation.period; + animation.fromValue = period.startLerp; + animation.toValue = period.endLerp; + } + + if (operation.timingFunction == &PRTweenTimingFunctionCAEaseIn) { + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; + } else if (operation.timingFunction == &PRTweenTimingFunctionCAEaseOut) { + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + } else if (operation.timingFunction == &PRTweenTimingFunctionCAEaseInOut) { + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + } else if (operation.timingFunction == &PRTweenTimingFunctionCALinear) { + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; + } else { + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; + } + + [operation.boundObject setValue:animation.toValue forKeyPath:propertyFormatted]; + [operation.boundObject addAnimation:animation forKey:@"PRTweenCAAnimation"]; + + goto complete; + } + } + } else if (operation.boundSetter && operation.boundObject && [operation.boundObject isKindOfClass:[UIView class]]) { + for (NSString *selector in animationSelectorsForUIView) { + NSString *setter = NSStringFromSelector(operation.boundSetter); + if ([selector isEqualToString:setter]) { + NSLog(@"Using UIView Animation for %@", NSStringFromSelector(operation.boundSetter)); + operation.canUseBuiltAnimation = YES; + + NSString *propertyUnformatted = [selector stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""]; + NSString *propertyFormatted = [[propertyUnformatted stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[propertyUnformatted substringToIndex:1] + lowercaseString]] substringToIndex:[propertyUnformatted length] - 1]; + + NSValue *fromValue = nil; + NSValue *toValue = nil; + + if (![operation.period isKindOfClass:[PRTweenLerpPeriod class]] && ![operation.period conformsToProtocol:@protocol(PRTweenLerpPeriod)]) { + fromValue = [NSNumber numberWithFloat:operation.period.startValue]; + toValue = [NSNumber numberWithFloat:operation.period.endValue]; + } else { + PRTweenLerpPeriod *period = (PRTweenLerpPeriod *) operation.period; + fromValue = period.startLerp; + toValue = period.endLerp; + } + + [operation.boundObject setValue:fromValue forKeyPath:propertyFormatted]; + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:operation.period.duration]; + + if (operation.timingFunction == &PRTweenTimingFunctionUIViewEaseIn) { + [UIView setAnimationCurve:UIViewAnimationCurveEaseIn]; + } else if (operation.timingFunction == &PRTweenTimingFunctionUIViewEaseOut) { + [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; + } else if (operation.timingFunction == &PRTweenTimingFunctionUIViewEaseInOut) { + [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; + } else if (operation.timingFunction == &PRTweenTimingFunctionUIViewLinear) { + [UIView setAnimationCurve:UIViewAnimationCurveLinear]; + } + + [operation.boundObject setValue:toValue forKeyPath:propertyFormatted]; + [UIView commitAnimations]; + + goto complete; + } + } + } + + } + + complete: + [tweenOperations addObject:operation]; + return operation; +} + +#if NS_BLOCKS_AVAILABLE + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + updateBlock:(void (^)(PRTweenPeriod *period))updateBlock + completionBlock:(void (^)(BOOL finished))completeBlock { + return [self addTweenPeriod:period updateBlock:updateBlock completionBlock:completeBlock timingFunction:self.defaultTimingFunction]; +} + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + updateBlock:(void (^)(PRTweenPeriod *period))anUpdateBlock + completionBlock:(void (^)(BOOL finished))completeBlock + timingFunction:(PRTweenTimingFunction)timingFunction { + + PRTweenOperation *tweenOperation = [PRTweenOperation new]; + tweenOperation.period = period; + tweenOperation.timingFunction = timingFunction; + tweenOperation.updateBlock = anUpdateBlock; + tweenOperation.completeBlock = completeBlock; + tweenOperation.wasPreempted = NO; + return [self addTweenOperation:tweenOperation]; + +} + +#endif + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period target:(NSObject *)target selector:(SEL)selector { + return [self addTweenPeriod:period target:target selector:selector timingFunction:self.defaultTimingFunction]; +} + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + target:(NSObject *)target + selector:(SEL)selector + timingFunction:(PRTweenTimingFunction)timingFunction { + + PRTweenOperation *tweenOperation = [PRTweenOperation new]; + tweenOperation.period = period; + tweenOperation.target = target; + tweenOperation.timingFunction = timingFunction; + tweenOperation.updateSelector = selector; + tweenOperation.wasPreempted = NO; + + return [self addTweenOperation:tweenOperation]; + +} + +- (void)removeTweenOperation:(PRTweenOperation *)tweenOperation { + if (tweenOperation != nil) { + if ([tweenOperations containsObject:tweenOperation]) { + tweenOperation.wasPreempted = YES; + [expiredTweenOperations addObject:tweenOperation]; + } + } +} + +- (void)removeAllTweenOperations { + for (PRTweenOperation *tweenOperation in tweenOperations) { + tweenOperation.wasPreempted = YES; + [expiredTweenOperations addObject:tweenOperation]; + } +} + ++ (SEL)setterFromProperty:(NSString *)property { + return NSSelectorFromString([NSString stringWithFormat:@"set%@:", [property stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[property substringToIndex:1] + capitalizedString]]]); +} + +- (void) update { + timeOffset += kPRTweenFramerate; + + for (PRTweenOperation *tweenOperation in tweenOperations) { + + PRTweenPeriod *period = tweenOperation.period; + + // if operation is delayed, pass over it for now + if (timeOffset <= period.startOffset + period.delay) { + continue; + } + + CGFloat (*timingFunction)(CGFloat, CGFloat, CGFloat, CGFloat) = tweenOperation.timingFunction; + if (timingFunction == NULL) { + timingFunction = self.defaultTimingFunction; + } + + if (timingFunction != NULL && tweenOperation.canUseBuiltAnimation == NO) { + if (timeOffset <= period.startOffset + period.delay + period.duration) { + if ([period isKindOfClass:[PRTweenLerpPeriod class]]) { + if ([period conformsToProtocol:@protocol(PRTweenLerpPeriod)]) { + PRTweenLerpPeriod *lerpPeriod = (PRTweenLerpPeriod *) period; + CGFloat progress = timingFunction(timeOffset - period.startOffset - period.delay, 0.0, 1.0, period.duration); + [lerpPeriod setProgress:progress]; + } else { + // @TODO: Throw exception + NSLog(@"Class doesn't conform to PRTweenLerp"); + } + } else { + // if tween operation is valid, calculate tweened value using timing function + period.tweenedValue = timingFunction(timeOffset - period.startOffset - period.delay, period.startValue, period.endValue - period.startValue, period.duration); + } + } else { + // move expired tween operations to list for cleanup + period.tweenedValue = period.endValue; + [expiredTweenOperations addObject:tweenOperation]; + } + + NSObject *target = tweenOperation.target; + SEL selector = tweenOperation.updateSelector; + + if (period != nil) { + if (target != nil && selector != NULL) { + [target performSelector:selector withObject:period afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + } + + // Check to see if blocks/GCD are supported + if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_4_0) { + // fire off update block + if (tweenOperation.updateBlock != NULL) { + tweenOperation.updateBlock(period); + } + } + } + } else if (tweenOperation.canUseBuiltAnimation == YES) { + if (timeOffset > period.startOffset + period.delay + period.duration) { + [expiredTweenOperations addObject:tweenOperation]; + } + } + } + + // clean up expired tween operations + for (__strong PRTweenOperation *tweenOperation in expiredTweenOperations) { + + if (tweenOperation.completeSelector) [tweenOperation.target performSelector:tweenOperation.completeSelector withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + + // Check to see if blocks/GCD are supported + if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_4_0) { + if (tweenOperation.completeBlock != NULL) { + tweenOperation.completeBlock(!tweenOperation.wasPreempted); + } + } + + if (tweenOperation.observers == PRTweenHasTweenedValueObserver) { + [tweenOperation removeObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue"]; + tweenOperation.observers = tweenOperation.observers & ~PRTweenHasTweenedValueObserver; + } + + if (tweenOperation.observers == PRTweenHasTweenedLerpObserver) { + [tweenOperation removeObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedLerp"]; + tweenOperation.observers = tweenOperation.observers & ~PRTweenHasTweenedLerpObserver; + } + + [tweenOperations removeObject:tweenOperation]; + tweenOperation = nil; + } + [expiredTweenOperations removeAllObjects]; +} + +- (void)dealloc { + tweenOperations = nil; + expiredTweenOperations = nil; + + [timer invalidate]; +} + +@end diff --git a/Pods/PRTween/lib/PRTweenTimingFunctions.h b/Pods/PRTween/lib/PRTweenTimingFunctions.h new file mode 100755 index 0000000..9b08b9b --- /dev/null +++ b/Pods/PRTween/lib/PRTweenTimingFunctions.h @@ -0,0 +1,82 @@ +/* + + These timing functions are adapted from Robert Penner's excellent AS2 easing equations. + For more information, check out http://robertpenner.com/easing/ + + -- + + TERMS OF USE - EASING EQUATIONS + + Open source under the BSD License. + + Copyright © 2001 Robert Penner + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#import +#import + +CGFloat PRTweenTimingFunctionLinear (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionBackOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionBackIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionBackInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionBounceOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionBounceIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionBounceInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionCircOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionCircIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionCircInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionCubicOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionCubicIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionCubicInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionElasticOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionElasticIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionElasticInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionExpoOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionExpoIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionExpoInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionQuadOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionQuadIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionQuadInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionQuartOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionQuartIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionQuartInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionQuintOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionQuintIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionQuintInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionSineOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionSineIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionSineInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionCALinear (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionCAEaseIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionCAEaseOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionCAEaseInOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionCADefault (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat PRTweenTimingFunctionUIViewLinear (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionUIViewEaseIn (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionUIViewEaseOut (CGFloat, CGFloat, CGFloat, CGFloat); +CGFloat PRTweenTimingFunctionUIViewEaseInOut (CGFloat, CGFloat, CGFloat, CGFloat); + +CGFloat (*PRTweenTimingFunctionCACustom(CAMediaTimingFunction *timingFunction))(CGFloat, CGFloat, CGFloat, CGFloat); + + diff --git a/Pods/PRTween/lib/PRTweenTimingFunctions.m b/Pods/PRTween/lib/PRTweenTimingFunctions.m new file mode 100755 index 0000000..5161d8a --- /dev/null +++ b/Pods/PRTween/lib/PRTweenTimingFunctions.m @@ -0,0 +1,230 @@ +/* + + These timing functions are adapted from Robert Penner's excellent AS2 easing equations. + For more information, check out http://robertpenner.com/easing/ + + -- + + TERMS OF USE - EASING EQUATIONS + + Open source under the BSD License. + + Copyright © 2001 Robert Penner + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#import "PRTweenTimingFunctions.h" + +CGFloat PRTweenTimingFunctionLinear (CGFloat time, CGFloat begin, CGFloat change, CGFloat duration) { + return change * time / duration + begin; +} + +CGFloat PRTweenTimingFunctionBackOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + CGFloat s = 1.70158; + t=t/d-1; + return c*(t*t*((s+1)*t + s) + 1) + b; +} + +CGFloat PRTweenTimingFunctionBackIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + CGFloat s = 1.70158; + t/=d; + return c*t*t*((s+1)*t - s) + b; +} + +CGFloat PRTweenTimingFunctionBackInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + CGFloat s = 1.70158; + if ((t/=d/2) < 1) { + s*=(1.525); + return c/2*(t*t*((s+1)*t - s)) + b; + } + t-=2; + s*=(1.525); + return c/2*(t*t*((s+1)*t + s) + 2) + b; +} + +CGFloat PRTweenTimingFunctionBounceOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + t-=(1.5/2.75); + return c*(7.5625*t*t + .75) + b; + } else if (t < (2.5/2.75)) { + t-=(2.25/2.75); + return c*(7.5625*t*t + .9375) + b; + } else { + t-=(2.625/2.75); + return c*(7.5625*t*t + .984375) + b; + } +} + +CGFloat PRTweenTimingFunctionBounceIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + return c - PRTweenTimingFunctionBounceOut(d-t, 0, c, d) + b; +} + +CGFloat PRTweenTimingFunctionBounceInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + if (t < d/2) return PRTweenTimingFunctionBounceIn(t*2, 0, c, d) * .5 + b; + else return PRTweenTimingFunctionBounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b; +} + +CGFloat PRTweenTimingFunctionCircOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t=t/d-1; + return c * sqrt(1 - t*t) + b; +} + +CGFloat PRTweenTimingFunctionCircIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t/=d; + return -c * (sqrt(1 - t*t) - 1) + b; +} + +CGFloat PRTweenTimingFunctionCircInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + if ((t/=d/2) < 1) return -c/2 * (sqrt(1 - t*t) - 1) + b; + t-=2; + return c/2 * (sqrt(1 - t*t) + 1) + b; +} + +CGFloat PRTweenTimingFunctionCubicOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t=t/d-1; + return c*(t*t*t + 1) + b; +} + +CGFloat PRTweenTimingFunctionCubicIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t/=d; + return c*t*t*t + b; +} + +CGFloat PRTweenTimingFunctionCubicInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + if ((t/=d/2) < 1) return c/2*t*t*t + b; + t-=2; + return c/2*(t*t*t + 2) + b; +} + +CGFloat PRTweenTimingFunctionElasticOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + CGFloat p = d*.3; + CGFloat s, a = .0; + if (t==0) return b; if ((t/=d)==1) return b+c; + if (!a || a < ABS(c)) { a=c; s=p/4; } + else s = p/(2*M_PI) * asin (c/a); + return (a*pow(2,-10*t) * sin( (t*d-s)*(2*M_PI)/p ) + c + b); +} + +CGFloat PRTweenTimingFunctionElasticIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + CGFloat p = d*.3; + CGFloat s, a = .0; + if (t==0) return b; if ((t/=d)==1) return b+c; + if (!a || a < ABS(c)) { a=c; s=p/4; } + else s = p/(2*M_PI) * asin (c/a); + t-=1; + return -(a*pow(2,10*t) * sin( (t*d-s)*(2*M_PI)/p )) + b; +} + +CGFloat PRTweenTimingFunctionElasticInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + CGFloat p = d*(.3*1.5); + CGFloat s, a = .0; + if (t==0) return b; if ((t/=d/2)==2) return b+c; + if (!a || a < ABS(c)) { a=c; s=p/4; } + else s = p/(2*M_PI) * asin (c/a); + if (t < 1) { + t-=1; + return -.5*(a*pow(2,10*t) * sin( (t*d-s)*(2*M_PI)/p )) + b; + } + t-=1; + return a*pow(2,-10*t) * sin( (t*d-s)*(2*M_PI)/p )*.5 + c + b; +} + +CGFloat PRTweenTimingFunctionExpoOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + return (t==d) ? b+c : c * (-pow(2, -10 * t/d) + 1) + b; +} + +CGFloat PRTweenTimingFunctionExpoIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + return (t==0) ? b : c * pow(2, 10 * (t/d - 1)) + b; +} + +CGFloat PRTweenTimingFunctionExpoInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + if (t==0) return b; + if (t==d) return b+c; + if ((t/=d/2) < 1) return c/2 * pow(2, 10 * (t - 1)) + b; + return c/2 * (-pow(2, -10 * --t) + 2) + b; +} + +CGFloat PRTweenTimingFunctionQuadOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t/=d; + return -c *t*(t-2) + b; +} + +CGFloat PRTweenTimingFunctionQuadIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t/=d; + return c*t*t + b; +} + +CGFloat PRTweenTimingFunctionQuadInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + if ((t/=d/2) < 1) return c/2*t*t + b; + t--; + return -c/2 * (t*(t-2) - 1) + b; +} + +CGFloat PRTweenTimingFunctionQuartOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t=t/d-1; + return -c * (t*t*t*t - 1) + b; +} + +CGFloat PRTweenTimingFunctionQuartIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t/=d; + return c*t*t*t*t + b; +} + +CGFloat PRTweenTimingFunctionQuartInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t + b; + t-=2; + return -c/2 * (t*t*t*t - 2) + b; +} + +CGFloat PRTweenTimingFunctionQuintOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t=t/d-1; + return c*(t*t*t*t*t + 1) + b; +} + +CGFloat PRTweenTimingFunctionQuintIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + t/=d; + return c*t*t*t*t*t + b; +} + +CGFloat PRTweenTimingFunctionQuintInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; + t-=2; + return c/2*(t*t*t*t*t + 2) + b; +} + +CGFloat PRTweenTimingFunctionSineOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + return c * sin(t/d * (M_PI/2)) + b; +} + +CGFloat PRTweenTimingFunctionSineIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + return -c * cos(t/d * (M_PI/2)) + c + b; +} + +CGFloat PRTweenTimingFunctionSineInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { + return -c/2 * (cos(M_PI*t/d) - 1) + b; +} + +CGFloat PRTweenTimingFunctionCALinear (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } +CGFloat PRTweenTimingFunctionCAEaseIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } +CGFloat PRTweenTimingFunctionCAEaseOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } +CGFloat PRTweenTimingFunctionCAEaseInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } +CGFloat PRTweenTimingFunctionCADefault (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } + +CGFloat PRTweenTimingFunctionUIViewLinear (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } +CGFloat PRTweenTimingFunctionUIViewEaseIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } +CGFloat PRTweenTimingFunctionUIViewEaseOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } +CGFloat PRTweenTimingFunctionUIViewEaseInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { return 0; } + +CGFloat (*PRTweenTimingFunctionCACustom(CAMediaTimingFunction *timingFunction))(CGFloat, CGFloat, CGFloat, CGFloat) { + return &PRTweenTimingFunctionLinear; +} diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj index 1c0f72d..3836d10 100644 --- a/Pods/Pods.xcodeproj/project.pbxproj +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -3,1088 +3,443 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ - 0097064E7F7D3F413161738CC5C25EEC /* MBProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 3504F10AAE9AFDB28FCB395022D5FE8C /* MBProgressHUD.m */; }; - 009F84889A3394E6EEA5694403D14C91 /* MBLHygrometerBME280PeriodicHumidityEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = AB7BB654211C9E0BD7A936321B39F4ED /* MBLHygrometerBME280PeriodicHumidityEvent.m */; }; - 00A07184BA261FC0F9E7A941DE025FD1 /* SQLite.swift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 557E2DBC953B749080CCF587EB527F41 /* SQLite.swift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0147A16532A6FC4DFD7956C09989FB5D /* MBLStringData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 798B5C3BB9132B9FDB5D673145BEC855 /* MBLStringData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 01BCA5FA1B77BF8E96CC28900AB0D77E /* MBLHygrometerBME280.m in Sources */ = {isa = PBXBuildFile; fileRef = BE3703D7CF94997EE0D61F4A95442741 /* MBLHygrometerBME280.m */; }; - 020A7B0219E3750F0A6BEA393AC1CFD8 /* MBLLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 3ACCB93D2A72146FE33631D032901428 /* MBLLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 02D0A4DFD38E7F2C645FEEC9207BB60E /* MBLPhotometerTCS3472Format.m in Sources */ = {isa = PBXBuildFile; fileRef = 15B1F99EC4F214371CF2234D359734D6 /* MBLPhotometerTCS3472Format.m */; }; - 04295D7285B17C002ABF746D836E97FF /* DefaultColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F05B37F717732E30D752E7C5D3F1201 /* DefaultColorPickerViewController.swift */; }; - 045BBA23F6CFD80FF1558F1091A8D297 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - 04EDF2F6371D812E267BAC4F8E9A6433 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - 05CD19DF403FF52E7CE83801B902DEA2 /* MBLGyro.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F5B2380B642EC90ACB0655B0A740AAC /* MBLGyro.m */; }; - 05D83FFA467CF5F869AB3108853AA661 /* MBLFirmwareBuild.h in Headers */ = {isa = PBXBuildFile; fileRef = A97E33CBC9D1460FA0817700D3D58EFC /* MBLFirmwareBuild.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 06BB08C3AFF8E49AF1E2BB80954D2432 /* MBLGyroBMI160AxisReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = DA51B5CBA61A46D223389903588000E7 /* MBLGyroBMI160AxisReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 06F7178BDB544DE97F5D1794C8DA06BA /* MBLGPIOPin.h in Headers */ = {isa = PBXBuildFile; fileRef = 839C1FE41EFED619CF628B14E7A166FA /* MBLGPIOPin.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0740676C2F5E1483FC4D07D8C4F8BB98 /* MBLGPIO.m in Sources */ = {isa = PBXBuildFile; fileRef = BFBCEE9347037627B22BCB8770DBE213 /* MBLGPIO.m */; }; - 07BA3B075F88C2170165585E0D3009C1 /* MBLAmbientLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 31EB4B1CA22089606877D26BE732188B /* MBLAmbientLight.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 07E77E69832FA381EFE3627F575866FF /* MBLMockPeripheralFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = EB29DCAE32FC6159EB64F81BA7AFD2E6 /* MBLMockPeripheralFactory.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0801F55D311EA5344545D6804E5C3402 /* MBLGyro.h in Headers */ = {isa = PBXBuildFile; fileRef = CE7DF8C67A67FDC3166FF2004E33F270 /* MBLGyro.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 087C7310465DE213F5EB5A3EBB437AA3 /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB39B281AA329E7B6D910316E475CB1 /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 08A965D1BCE12AE43CD46A1227E1C341 /* MBLBarometerBosch+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1455523005F45E1DEB1BF69539D10967 /* MBLBarometerBosch+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 096D3C3E8BE1F5EB6D9D69C45F1E8BE1 /* MBLTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34088EF7AE33D968FAB900636386D40C /* MBLTimer.m */; }; - 0A1D9145798728AAC724FED0C2C93556 /* MBLFirmwareUpdateInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = E75D64B6623706FFFE53E3FCE670A8A0 /* MBLFirmwareUpdateInfo.m */; }; - 0A9D62EE02E8812CE4625F142296428B /* MBLAccelerometerData.h in Headers */ = {isa = PBXBuildFile; fileRef = 97DE674DA17D28837EEE190D55B1C72C /* MBLAccelerometerData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0AA33EBB857A5205F87C09CCB99EAC74 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - 0B41E44FB11C5A3D15B89E42C9CEE1A2 /* MBLI2CData.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C46D371D69D1FF5F5FA74A437E899D3 /* MBLI2CData.m */; }; - 0B7228B73B7A2204932286C042D42E4E /* MBLBluetoothPeripheralMock.h in Headers */ = {isa = PBXBuildFile; fileRef = 99962F735427ACDF3EC96AB3A35302A3 /* MBLBluetoothPeripheralMock.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0BA10E7421D5BCF6526536185D556375 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51E77D088B0EFA67C576F729BE56D26F /* Connection.swift */; }; - 0BB895E77A96C2676EF5F978B3A230E0 /* MBLMechanicalSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = F85FE393EC8D5A5BB2C2B3BB82E4C961 /* MBLMechanicalSwitch.m */; }; - 0CA4B372C03A35AAFF0C800916876278 /* MBLBarometerBoschPeriodicAltitudeEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C42D16CF91748AA1CCEA014D3D93140 /* MBLBarometerBoschPeriodicAltitudeEvent.m */; }; - 0D474A495D7CF25B30ECAB82AB39836F /* MBLSerial.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EDC6817E50BBE358090BE6382A9D43A /* MBLSerial.m */; }; - 0D61EF001DF1E45F9956DFCB75B21362 /* MBLCorrectedFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 8491C15C76BF353764E258E377D0C2E8 /* MBLCorrectedFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0E6D8BFE0AE233753BCBDCA514A74C0E /* MBLAccelerometerBoschDataReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 15F2D265A6C06CC541A908919C149B97 /* MBLAccelerometerBoschDataReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0EDB699967ABEB02EB092AF24EE82293 /* MBLAmbientLightLTR329.h in Headers */ = {isa = PBXBuildFile; fileRef = E00038F84A6C775FE43D73FCB163BDFC /* MBLAmbientLightLTR329.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0F1BDD331C0BF9B6556C473CFF9C9BE2 /* MBLAccelerometerAxisReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 71CB5DA203DD44720C6516AE4751BDF8 /* MBLAccelerometerAxisReadyEvent.m */; }; - 0F334002FACD61A79A23D65C4986FC59 /* MBLNeopixelStrand.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A3A5964E423BCF12F97938C3CE21151 /* MBLNeopixelStrand.m */; }; - 0F8FD28DE9A5B56025329EDD7366A8D5 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C0E0758C2BBAC987D1296921D92C489 /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1009D17A0D618C526011C9AA19F5F8F2 /* MBLLED.m in Sources */ = {isa = PBXBuildFile; fileRef = AFA6D3F966A7D6C6CC905F69C04ED4DF /* MBLLED.m */; }; - 108F412D144ABE030AEA38504E1DF359 /* MBLDataSample.h in Headers */ = {isa = PBXBuildFile; fileRef = ADE85F46048EC1F3C36566473CA0DD97 /* MBLDataSample.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 10B1604C0D6BA26700F79DBDB92F6EE7 /* MetaWearPrivate-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4443E63922CECE498D2F090F518F1509 /* MetaWearPrivate-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 111811351D51010901E4B4B8CD1633DA /* MBLMagnetometerData.m in Sources */ = {isa = PBXBuildFile; fileRef = 78BE644057CFCCF385C1B31DD709F1C6 /* MBLMagnetometerData.m */; }; - 112A40C3F3E10E913219C547E2278636 /* BFTaskCompletionSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B13756AF4593D9371410055A4AE2417 /* BFTaskCompletionSource.m */; }; - 112B91D60A3D6D2F015A40E20CCF42E6 /* MBLNonVolatileState.m in Sources */ = {isa = PBXBuildFile; fileRef = E88E61270713AD28CFA48C2A09CE49B4 /* MBLNonVolatileState.m */; }; - 1139BBBBBAF0F3DD5D3E76D4AAE74DAE /* MBLAccelerometerMMA8452QFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F61A31F5F27DBB0BD934BC6571F76C1 /* MBLAccelerometerMMA8452QFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 11C9627A459E29CC6BA76AB490BABF44 /* MBLDependentData.m in Sources */ = {isa = PBXBuildFile; fileRef = 710C8C193172A27E175ED44AD3F04CDD /* MBLDependentData.m */; }; - 12B5141E9F82B27014FD48968EACF549 /* MBLI2CData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A8C11505635DEA31ECB90490AD1B7C0 /* MBLI2CData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 13119889C1ED501552726A7BC718E1A6 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D0EAE6159180C30086D9739F578720 /* Coding.swift */; }; - 14DBF52DB826D0A1391DDA0EEF1C8AED /* MBLCategoryLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 666047892D4382C05D1CA2A8AD020509 /* MBLCategoryLoader.m */; }; - 14E6067619010FD3F365BAAF05B78B58 /* MBLAccelerometerBoschRMSFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 1279087722BFA08A2563C4186EA02B32 /* MBLAccelerometerBoschRMSFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 15EBC48751B6E945CF6D6F958B5C56FD /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81E83D2644E55250C1FBDC664E9792F8 /* FTS5.swift */; }; - 15EF18D5B21AC5FF492796700C5B1324 /* MBLEulerAngleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 38AC511C52A3160D8BFA36D301F88345 /* MBLEulerAngleData.m */; }; - 15F05EF2113378020428917620F96FF8 /* MBLiBeacon.m in Sources */ = {isa = PBXBuildFile; fileRef = 05FA13B1682546E889E7F5EF918EDEF5 /* MBLiBeacon.m */; }; - 1639DF4A53A68B459C2EA18C387A6A54 /* MBLAccelerometerBoschFlatFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F5F92185806E08CE8B628A488ACF9DE /* MBLAccelerometerBoschFlatFormat.m */; }; - 164808D1E9C4B86AB4D4FA6FDD4EF52A /* MBLRGBData.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A8C9E3945A6C2788CB41E514EEA131 /* MBLRGBData.m */; }; - 16D461686E7092213D7E9926341FC656 /* MBLBitmaskEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = CF31C98488A03AF1D8E488DD1D680615 /* MBLBitmaskEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1749A31535DF81B1B3E075192D849765 /* MBLConductance.h in Headers */ = {isa = PBXBuildFile; fileRef = D85D1057312D207DA8D70181E021BD2C /* MBLConductance.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 19121B1C97200A025ECAED7407913066 /* MBLGPIOPinChangeEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 362DE09F372E1F53540DDE7687212B9C /* MBLGPIOPinChangeEvent.m */; }; - 1A4807E59E5219D6D0605E8DD37D7198 /* MBLMetaWearManager+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 02D36FC3DB28544278D49A5526ED7097 /* MBLMetaWearManager+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1B007F916C7DC8CB13580EFAE4F7D6AF /* MBLAccelerometerBoschFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 95F84F11F10A37945DEACE2F521BAF09 /* MBLAccelerometerBoschFormat.m */; }; - 1B3833656A4E11A557DD596A3B4BF8F5 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F64CD2286F8C395213E1759FB5D210A8 /* CustomFunctions.swift */; }; - 1B4EEDA4C33178BE372479CED54F4C99 /* MBLGyroBMI160DataReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 56CE0C94F84E1FF8FDAF0132715EE59D /* MBLGyroBMI160DataReadyEvent.m */; }; - 1BF7821F0E1AE58CCF889268894ECEFE /* MBLAccelerometerDataReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 27375EFF0029352930FC350FA1958789 /* MBLAccelerometerDataReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1D03237EF9F22AFEAAEECAF8853E5FAB /* MBLBarometerBoschPeriodicPressureEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DD64AB34CC0A56FD03310D59BD66415 /* MBLBarometerBoschPeriodicPressureEvent.m */; }; - 1DC255F222925038C5C66AB2EC838BE8 /* ComponentSliderDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80C1FEEFB923E9AAEF622948ABBBCB82 /* ComponentSliderDelegates.swift */; }; - 1EBCA4F61F06DDF25EBF84A12E325D6D /* ColorPickerControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0898A84F8AFB64E5EA38D125E0BA00AF /* ColorPickerControllerProtocol.swift */; }; - 1F332C51AB92D2E9E46BB0D5CBEE2E80 /* MBLSPIData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7622CCBF862B6B768ED7FBD7F3DA490F /* MBLSPIData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1F3AE218EA2C44267A07C339C5E9D27A /* MBLNumericData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E243FEF6D81DE5AFC9EBD3BDA3C420C /* MBLNumericData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2063F0C00C82B38FD48192CDAB1760AD /* StaticDataTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD032BAD9297C34CC59A56B6F37632D8 /* StaticDataTableViewController.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; - 20840E7E1F6D316A47C8A6C64DEB3AFB /* MBLGPIOPin+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2041271A141C45AC517D17888B5AB562 /* MBLGPIOPin+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 225B930E6E18E4BB031DF2266B16CCF4 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFDCC96BE3FFD250CD91415D4C8162F9 /* CoreFunctions.swift */; }; - 226C4C2401451A6BCB171A06ABDC69DA /* MBLFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = C9316C8FB669D06A57EB51231B16FFE5 /* MBLFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 234BE91335646A9ADF3340A2F8207CDF /* MBLANCS.m in Sources */ = {isa = PBXBuildFile; fileRef = 579F7BDE884513135251D390A9416BBE /* MBLANCS.m */; }; - 24387CE4EB22A66598C11C57658EC110 /* MBLGyroBMI160.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CF9E215545AF0D84ECF3C631CC3958C /* MBLGyroBMI160.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 248638FE576616C9ED1D73AC09D03130 /* MBLLoggingV1.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B2496EFD101ED42CCB429E14049A6A6 /* MBLLoggingV1.m */; }; - 27355E532094E863B6034A77D65040C5 /* MBLQuaternionData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CC01879C87DED7F6F3014CC9690267C2 /* MBLQuaternionData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2794F4AB396F19BB731D0F584E973C1A /* MBLHapticBuzzer.m in Sources */ = {isa = PBXBuildFile; fileRef = 79009A415E1CA0B87F12D4F51E03E275 /* MBLHapticBuzzer.m */; }; - 2B027C37026176ABA5B48E7F0DE2C6DE /* MBLHygrometerBME280PeriodicHumidityEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 1DB3F0AF535DD95F163B334A50BC36DF /* MBLHygrometerBME280PeriodicHumidityEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2D9C366A0248B39C56B888892BC52EB2 /* MBLGPIOPin.m in Sources */ = {isa = PBXBuildFile; fileRef = 5381E2D2DD1B9D824DD465B2CF527DAB /* MBLGPIOPin.m */; }; - 2E0E829853E688E1425CDC52E1EFCDB2 /* ColorControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 060C6688EBD31FE399EEF457BEB46DF4 /* ColorControl.swift */; }; - 2F5EB691F51632E5A37FA3F67CACDA97 /* MBLBarometerBMP280.h in Headers */ = {isa = PBXBuildFile; fileRef = CD5BAE72308C847F0DDDC961B9D1F1EB /* MBLBarometerBMP280.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 2FF483BFBDD47B9E1E507E3CCD6E0F4D /* MBLAccelerometerBoschFlatEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C3FDF931FB3F22106AEB74ADE3EE6B0 /* MBLAccelerometerBoschFlatEvent.m */; }; - 30555802874EDB3C6132B1B31470922B /* MBLGyroBMI160Format.h in Headers */ = {isa = PBXBuildFile; fileRef = 76048F5B3375D5784C0B5324D1BE08D7 /* MBLGyroBMI160Format.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 310AE1E2E5EE650ED3EC90ABE54482D3 /* MBLNumericData.m in Sources */ = {isa = PBXBuildFile; fileRef = 4924598DFBB638C24E440E1CE354CBCB /* MBLNumericData.m */; }; - 3278B4E93ACF924EDF92EBD6AE9D2FDC /* MBLI2C.m in Sources */ = {isa = PBXBuildFile; fileRef = 8970EEE842F7C944B400E85182FA4D7E /* MBLI2C.m */; }; - 32FF9EF7262310025BC6C8A41046122F /* MBLExternalThermistor0.m in Sources */ = {isa = PBXBuildFile; fileRef = CCF4AAB7D3A5091626ADDD67F202425B /* MBLExternalThermistor0.m */; }; - 33076C7869DF4147F49A0F04A184D99C /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 18BCDEA1BB8E632240F8D90D2EC39ABC /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 3418D0C7503FF9243E8BB4CCBD972DE6 /* MBLMagnetometer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C7BB0D32F5255CE1D02B13A3FA4B89C /* MBLMagnetometer.m */; }; - 34CF03D6C264FF035EA81D283DD51D73 /* MBLTemperature.m in Sources */ = {isa = PBXBuildFile; fileRef = 3546FE1448811DA0824B98448DE651B1 /* MBLTemperature.m */; }; - 34F8756D7BC88420992B078B9E96E5CB /* MBLMetaWearManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E596EEE3CD039BB60C73DA5353A84FB8 /* MBLMetaWearManager.m */; }; - 3689B88517E22DD7FE2301D599CFE214 /* MBLTemperatureV0.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC9FC024573932A6B57179D1A27FBC1 /* MBLTemperatureV0.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 373FF98F6ED4C09EBBBDC23A104D8021 /* BFExecutor.h in Headers */ = {isa = PBXBuildFile; fileRef = B634A03BAB223550C28DA4D4C43BCE38 /* BFExecutor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 38B840E7146BFA32100316A034CA1AC4 /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 95E4D7D504BD6D0C20D213018DE0D8C9 /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 391C8178D39D54002F22D51ACC011F7D /* MBLLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = B66025F0A7A7B300D691863FA50F11D7 /* MBLLogging.m */; }; - 3AFCEE50ED0FB18B383A344A59C1C9CE /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35AA2A32130BF6780B993286A8E753CA /* Expression.swift */; }; - 3B127F5F000ADF67A4FE001045BDAA2F /* MBLPhotometer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 03AAABEF834082B42949BFF22663E639 /* MBLPhotometer+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3B3F2F93DC339D289C849C393B9B1A70 /* MBLAccelerometerMMA8452QOrientationFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C98A12DCBC5C73CA0813B0F0BB29E4C /* MBLAccelerometerMMA8452QOrientationFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3B4FDE53274DA00790C4262C8B3BEA98 /* BFTask+Exceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 163E1C0C54636289C825D0724BD976AF /* BFTask+Exceptions.m */; }; - 3B7FEAF877F9F1A1C6B80582B68ADD8B /* MBLTimerEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F41492695945037081DBB883B13048 /* MBLTimerEvent.m */; }; - 3C2241BAABC2201EA6AFC9A832828D37 /* BFCancellationToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 252750A7AFDD794CFFE923FCE3F738ED /* BFCancellationToken.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3C607D3FE99007F2B8314642499E338D /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4196509A0F6F6008BEA13E7494AE5C80 /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.m */; }; - 3CB259984A8E20104D9EEF6CD36FA626 /* MBLEntityEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 595E3AE5886C8CFBDE5B91E71DF980BD /* MBLEntityEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3D6693BBDE954357B923A260F6B25286 /* MBLMetaWearManager.h in Headers */ = {isa = PBXBuildFile; fileRef = FDBCB4D513E8E858685C0A0E1D33FD35 /* MBLMetaWearManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3DB28F2B0FB2476C765A581F3FCDB79E /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0365AA1E5BCF7893919B18CED0199C8 /* FTS4.swift */; }; - 3DB5CF33BE913307E82F075D2F01D04E /* MBLStringData.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A99D023D267E648A3B2CCD8CC0F7 /* MBLStringData.m */; }; - 3DCB3952569C4270BF3C3E92B3DDB02B /* MBLAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 30278A2896EBED27D7B8B4A499988944 /* MBLAnalytics.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3E16D118FE5520E9ED97FEFCB2D6FC23 /* ColorControlContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52348E26326B74D99A9556A7F07D4FA4 /* ColorControlContentView.swift */; }; - 3E7D42CBB29E683F4B21535A748ED234 /* RectangularHSBPaletteDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BC8D097C45C807B6B0F9759CE423128 /* RectangularHSBPaletteDelegate.swift */; }; - 3E950E56661FACDAB6426E793300F06C /* MBLAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = C3DBA18C39DFD63A6E34ED9F78739553 /* MBLAnalytics.m */; }; - 3EDCEA8E82B93C08617911C308E2B087 /* MBLDataSample+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7784E31355FEBC6941C37143FAD1BB78 /* MBLDataSample+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3F5B74E52A297C4E329E326B84636A4D /* MBLOrientationData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E2EB1A561C2951A3F29D98C21C6D68F /* MBLOrientationData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3F74D86D18CFA6D819272FE07F49DC1F /* MBLMechanicalSwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 5447D64353ADF313B6DDA3764B0AA4ED /* MBLMechanicalSwitch.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 413569643E45773A84A347CD2FC21592 /* MBLGyroBMI160DataReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = D47CF02ABCBDAA6FB17E801921105666 /* MBLGyroBMI160DataReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 414EEDDA388C02134F293D3A237BB09E /* MBLAccelerometerBoschFlatData.m in Sources */ = {isa = PBXBuildFile; fileRef = 65D6DC10F5E74FFA08C8CED7FFFD778C /* MBLAccelerometerBoschFlatData.m */; }; - 41D3F2967EE6E602190072C480F327EE /* Bolts-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F671A45BF53AE08C5B8E3BE22A901D1 /* Bolts-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 42AD0F3D9A465A754CA101206B10C5B3 /* MBLAccelerometerMMA8452QRMSFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = B60C6D4316257A8592A9C8FFD2E4C1D2 /* MBLAccelerometerMMA8452QRMSFormat.m */; }; - 43092322CA985D0BA07B0354746E3EF9 /* MBLAccelerometer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D1C71B13C43496337847E0080653C90C /* MBLAccelerometer+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4332541495D7A23452A6A579D2160011 /* MBLAccelerometerBMA255MotionEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 10F5BAC0567A9C558CC3AB8CF1EE3D1A /* MBLAccelerometerBMA255MotionEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43B68D64024BBB36520CCFF34D2CC1D8 /* MBLAccelerometerMMA8452QRMSFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = C3A391E839582AAF0BFB4FE1830EE8BE /* MBLAccelerometerMMA8452QRMSFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43DD5997299CE6CABAF398150937871A /* MBLGyro+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 23A28F0383C296A9AB950400B3387147 /* MBLGyro+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 43FDD430CD293526E377E52D4573AF34 /* MBLBluetoothCentral.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E97D61EA17F90FA1A96C5EA492CA4FB /* MBLBluetoothCentral.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 441F2A14F7F49F762684F592CE245FFF /* PRTweenTimingFunctions.m in Sources */ = {isa = PBXBuildFile; fileRef = C7CFF911E5E62F4576D5F62C22700FF5 /* PRTweenTimingFunctions.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; - 455CACD6876F9D77775FB1DB3E7F32B3 /* PRTween-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 84ED3110C21AB37CCDDF68B23BA0B774 /* PRTween-dummy.m */; }; - 45C09373E5F1AFAEA177220C43931989 /* MBLSensorFusion.m in Sources */ = {isa = PBXBuildFile; fileRef = F715537652AB81FD9ECC102350E1CD57 /* MBLSensorFusion.m */; }; - 45D9172EC3A085B300D1D3574E8B1A3C /* MBLGyroBMI160+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 94F8B62730BE54CC80EFCB063CE8DB0A /* MBLGyroBMI160+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 475ECCF39C1C9EFB6618D28B823E4807 /* MetaWearPrivate-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 9412CC7AD155C9478A8CAAC3A112EDDD /* MetaWearPrivate-dummy.m */; }; - 47E0C0DB2BBAB310D70EB1F307089699 /* ColorPickerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FD03161B220A16CBBC96747CD6F2A10 /* ColorPickerDelegate.swift */; }; - 484358B01F3C24B4E0CF024F8D40AF8B /* MBLAccelerometerBoschLowOrHighGEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 0841698E1D51A9F98486360941631FC4 /* MBLAccelerometerBoschLowOrHighGEvent.m */; }; - 48CCDC527BFC92E2B5409E8E5AA83C21 /* ColorPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75A53299EEC86ABF9064680EBDC08974 /* ColorPickerController.swift */; }; - 490107A856F476787977D8E183EEC0D2 /* MBLRGBData.h in Headers */ = {isa = PBXBuildFile; fileRef = 997426A3EEBF7C2EB7DE297CA7BC5413 /* MBLRGBData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 497D53BB698030F17746C7FB4FD5039F /* MBLFirmwareUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C7F2255FF56AF376C85585754EF2C3A /* MBLFirmwareUpdateManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 49BC4B1FB2948A43E35EABB82D5E4A24 /* MBLEntityModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A32C7003976797CB7E261BC2F4EFA18 /* MBLEntityModule.m */; }; - 4A7A63984642CA0EBCFE8C43F8765D7E /* MBLGyroData.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A1E8DAD74C3585D5AF1D9889AB1298C /* MBLGyroData.m */; }; - 4B292CE74CB55C12F36BB25AC2CE00B7 /* MBLBarometer.m in Sources */ = {isa = PBXBuildFile; fileRef = 67E7ECC3E54031D450010ADCF4BE7A02 /* MBLBarometer.m */; }; - 4B91A41B9BCE19D03B6D92A4F6B5BF86 /* MBLGyroData.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C2249EBCE5DF74C7202C4C1603B5C78 /* MBLGyroData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4CA9B1A258191CF5DEB8DF9D446656D9 /* BFCancellationTokenRegistration.h in Headers */ = {isa = PBXBuildFile; fileRef = 80F929B0B2C6125D7E424E4A8D45F92F /* BFCancellationTokenRegistration.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4D933D264135A38C46269F0B1ADE267C /* MBLLoggingV0.m in Sources */ = {isa = PBXBuildFile; fileRef = 42E7ABDEEF2B747C41A103067522FC2D /* MBLLoggingV0.m */; }; - 4F3D3E2B42F11AD0C43C29BB45443D5F /* MBLAccelerometerData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B364C63A62EB39DC5DD8139922E3E5A /* MBLAccelerometerData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4FFF9461510B01AE1E38C236E459848B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - 5043CFE6ACCA434053B850AA26C6468A /* MBLLoggingV0.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C4F3EEAA0ADC98A3D8086E8AA82416C /* MBLLoggingV0.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 515290B0590481E8CBE96FBBE0737386 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BA3AA18F797CA8C3E4DEBA6DD071F4 /* Helpers.swift */; }; - 521DD2B1C4D2CB2D98707B924AE1542F /* PRTween.m in Sources */ = {isa = PBXBuildFile; fileRef = 862315B9E7FA3F370EF8449599E625A0 /* PRTween.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; - 52A63DD22AEBB030D3112A41DABCD95B /* MBLAccelerometerMMA8452Q.h in Headers */ = {isa = PBXBuildFile; fileRef = AEE6B2B57E2658D16BB004197E73ADB7 /* MBLAccelerometerMMA8452Q.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 52ADFFADF505CD10EAC7505DCEAE2C0A /* MBLAccelerometerBMA255MotionEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D44113003212D13E02B7FF7483FF3C2F /* MBLAccelerometerBMA255MotionEvent.m */; }; - 532AD22B6AB432104B999955188A7041 /* MBLSerial+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F861CFB25E168725F2FA7AB07557676C /* MBLSerial+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 53BF73FDAB4554F33A0B48DF814C0BC5 /* MBLAccelerometerBoschFlatEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = B279E17CC4C99B56C4AB6FA7871B3A09 /* MBLAccelerometerBoschFlatEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 54532A80EC7747EB2E21582D91C026DA /* MBLEulerFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 4466835466E43CAEA302DA6589EA68F8 /* MBLEulerFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 54D4ADE850800376599BD698B1961A5E /* MBLEntityModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BC4C89BFE4515AEAFA90A8F0A2DB780 /* MBLEntityModule.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 55A5EAEE17873EEE0290A88B78E5E47F /* MBLSPIData.m in Sources */ = {isa = PBXBuildFile; fileRef = A0BEA4B8CB2275B94D4A678EEA3F9726 /* MBLSPIData.m */; }; - 567FA4BF489C0DA73E0DAED192632095 /* StaticDataTableViewController-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ACD94175F05C0E29F06F1928D1B2923 /* StaticDataTableViewController-dummy.m */; }; - 56C52024171B7188E3144EF14E8F832B /* StaticDataTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 69873ABB652364D99E9A6C4958E48A7B /* StaticDataTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5777482CB97E20747EED2860DCC0078F /* MBLData.h in Headers */ = {isa = PBXBuildFile; fileRef = CD20F39380856BCE4A46A32AB8DD3FED /* MBLData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5793C02AA8B4CCC0D886165799B5E406 /* BFCancellationToken.m in Sources */ = {isa = PBXBuildFile; fileRef = A31D7E886BA2EE4D7FE6732E7F0F8C08 /* BFCancellationToken.m */; }; - 583410DAC575A9BB1C11E658752463EF /* MBLAccelerometerMMA8452QOrientationFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 8499C6937A05616246FD6735CF490211 /* MBLAccelerometerMMA8452QOrientationFormat.m */; }; - 58C91B4AB36E6B16421106CA634C58EF /* MBProgressHUD-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D042F1A9160E0C2DD382751B794F95CF /* MBProgressHUD-dummy.m */; }; - 58EC2EF024941BC8E4FF4FE9F2698C14 /* MBLAccelerometerMMA8452Q+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD9FA47B74B1AC08CBDFD649C1EDBAF /* MBLAccelerometerMMA8452Q+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5A1A16EBF2EE42DA6743EAA3004201BF /* MBLBarometerBME280.h in Headers */ = {isa = PBXBuildFile; fileRef = 44131CFFCDE00E71F5EACDF06483240F /* MBLBarometerBME280.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5B47010C4D6B466C25D14893C7CF13DC /* MBLMetaWear.m in Sources */ = {isa = PBXBuildFile; fileRef = C21E4B182C7E88A6C2637D759E596E90 /* MBLMetaWear.m */; }; - 5B825EBBB25135A58E16E91C69ABCFCA /* MBLBarometer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F0D701BF8EC069496B3C43FFCAAC84C8 /* MBLBarometer+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5BAC1EF86D0E57E44E404B2796993561 /* MBProgressHUD-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F05E3F8AB2E722ADB3A3663D0DE873B /* MBProgressHUD-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5BB334E271C56FAB07D551A09A1C7A35 /* MBLMacAddressFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 311E32021E8602317EB6D1575470819D /* MBLMacAddressFormat.m */; }; - 5BC0A54144FE09136D30DC97003FB7BE /* MBLConversion.m in Sources */ = {isa = PBXBuildFile; fileRef = 68755AC626C33567BB3E422E830BFF81 /* MBLConversion.m */; }; - 5C83BE1C9F476163517EA0C0ACBA4482 /* MBLFirmwareUpdateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F8D2F802D75DFA0F0B9B216784D8953 /* MBLFirmwareUpdateInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5CEFF7EB8BCC2687ABB478D0204F5A36 /* MBLExternalThermistor1.h in Headers */ = {isa = PBXBuildFile; fileRef = 519EE35C72315D1A7AADC923C91B38E7 /* MBLExternalThermistor1.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5D79D26D1BE6505D813C8F7954957FE6 /* SQLite.swift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FBE2315754253B9086E8727EA5D32D39 /* SQLite.swift-dummy.m */; }; - 5E47EC775681C59C467F5954D516BE2D /* UIViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B33CDBDF1B9436C886A3943A9CFBF3A7 /* UIViewExtension.swift */; }; - 5E7E728EF90BDE8D85E46993DFD2A041 /* MBLDataSample.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A92E56CD0DA9567C0D2C38269029A45 /* MBLDataSample.m */; }; - 5E919B07455AD8D8CB6C2F57917580F2 /* MBLBluetoothCentralMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0AEDBAEC7541B87CE8246EF7E685BF /* MBLBluetoothCentralMock.m */; }; - 5F83A759FD27D04CD4B13BDAF9222F1A /* MBLMockPeripheralFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = BDCD67FA16C0A10BB731D87465C6E05F /* MBLMockPeripheralFactory.m */; }; - 5FAF9A60E2E7DF6459B806B2EA13A02F /* MBLProximity.h in Headers */ = {isa = PBXBuildFile; fileRef = A74539E4276BAD6B5B7AD628754C5504 /* MBLProximity.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5FE7A063E370709D0B60DA0BDDE963E3 /* MBLEulerFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = BE11AF986689B3ACFB86F3F7A54B71B7 /* MBLEulerFormat.m */; }; - 607D6C4B48514522D839AECA18D5C01E /* MBLFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EE225CB21810DD025D78280C1B2474F /* MBLFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 611443C633820C7EDA5FA856D856EB01 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E62E73A944F0141732701B301FCFA95B /* Foundation.swift */; }; - 61ACDE06EBBB628AF0C3028B938ECCB8 /* MBLRMSAccelerometerData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = A50E162915108843410E01B430AFCF82 /* MBLRMSAccelerometerData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 61C2B0B2A307903749C1D83DF203718B /* MBLANCS.h in Headers */ = {isa = PBXBuildFile; fileRef = 63F79A6649FBFB5574186379DCD1D421 /* MBLANCS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 62B0AE5C69C426B0613E35C1105A9263 /* CGPointExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2419ECD02B38092140406C63872E7680 /* CGPointExtension.swift */; }; - 62E75F5D23D9CF185B86551D0FB03ACE /* MBLBarometerBoschPeriodicAltitudeEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = CE750EE45CE8CF012A77D168A395CC3A /* MBLBarometerBoschPeriodicAltitudeEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 63088E344259927A411F55D1F5E52D68 /* MBLBarometerBosch.h in Headers */ = {isa = PBXBuildFile; fileRef = CD543DD9A37CED8E5D798EE760111A9D /* MBLBarometerBosch.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 635314D5BE8A729A2701E5B7B4E88E11 /* MBLGPIO.h in Headers */ = {isa = PBXBuildFile; fileRef = 513FAF97F4FE15694C4CF4A8304BBEF3 /* MBLGPIO.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 63A94CE8B3BA5E885E9B60D64B51C2CD /* Pods-MusicalCaneGame-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 478174D0C87B9553375A4A8103192D96 /* Pods-MusicalCaneGame-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 644C0E9C4C1C4E43BB139B07AB4AF614 /* MBLRMSAccelerometerData.h in Headers */ = {isa = PBXBuildFile; fileRef = 800CCDF7A423E20D6E58606E2618A753 /* MBLRMSAccelerometerData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 65238E3396193C34F7CC14E6FCF5F846 /* MBLBitmaskEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 59B5866AFB868B2385488D9FF72A80D8 /* MBLBitmaskEvent.m */; }; - 65C13E997A2C177271DAE0308C22194A /* MBLBarometerBoschPeriodicPressureEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 31F2FE25B77174C58D106A70256387EB /* MBLBarometerBoschPeriodicPressureEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6658CA9DED4180C6E730A30CB5F2C845 /* MBLBarometerBME280.m in Sources */ = {isa = PBXBuildFile; fileRef = 61EBB4660D809D8033457C2CE80411B9 /* MBLBarometerBME280.m */; }; - 666E5C596955D4F4587873DD4ABF98F3 /* BFTask+MBLExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B005DFE326C47396B8658C6BC3E3088 /* BFTask+MBLExtensions.m */; }; - 66B97A52F51380108199725E357232F9 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A43CC85B18E8ACDE0E384BBD649438C /* Setter.swift */; }; - 66FA9D9451995E3D50248954D900A9B9 /* MBLGPIOData.h in Headers */ = {isa = PBXBuildFile; fileRef = EDBDC73FE0EB39A12FCDD97E86BC4491 /* MBLGPIOData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 67CDFE07449FC2151D6CE314BDD143E7 /* MBLOnDieTemperature0.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB907B756FEC95ABE36EB6962A359B1 /* MBLOnDieTemperature0.m */; }; - 67E941CADB3CDDEEDF8CE4EE4A4A05BB /* MBProgressHUD.h in Headers */ = {isa = PBXBuildFile; fileRef = 799D9302D1CE2454BF686DF875D0320A /* MBProgressHUD.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 680A98138C269CA0E7A7FEC58978C2A9 /* MBLBarometerBMP280.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A4226CABDC9A7A1AB311F018CC7FCFB /* MBLBarometerBMP280.m */; }; - 6816B32CDE508E3A8718BDFF40DAC085 /* MBLAccelerometerTapEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2467DB704F5E928FE637376D0A496718 /* MBLAccelerometerTapEvent.m */; }; - 68433728E8193F655A3854DF8AD5C76A /* MBLTriggeredRead.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EFE1999F17421FBBC0203397DD7308E /* MBLTriggeredRead.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6899FB350AA150209056CEDBB36F1E6E /* MBLTimer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 56864443F16243B0215C7D7BBA02BF12 /* MBLTimer+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 68BE1D1D8269258A13805590BA9BFCFC /* MBLMetaWear.h in Headers */ = {isa = PBXBuildFile; fileRef = 5391ECE3ABD3B21D5B420350C96853A3 /* MBLMetaWear.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 68D0171DA92D9EFEC1E43BF9B5ABC35B /* MBLOrientationData.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C8301370646F1F03A57FE5982C6618B /* MBLOrientationData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 69128D7359FA88A5AD353CF5D77A8837 /* LimitedGestureViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BAE0694187091665D4BF2CC5C546B7C /* LimitedGestureViewDelegate.swift */; }; - 6947B5E5DEFD4E9FAE8C70146D05AD09 /* MBLDeviceLookup.h in Headers */ = {isa = PBXBuildFile; fileRef = C36B46123D96EED8AFC393D73A505F49 /* MBLDeviceLookup.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6965BE90DB2A4F28DDC5EE2B31B61433 /* MBLEulerAngleData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B79044677BC189DBE3E11CA1A5D45456 /* MBLEulerAngleData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 69E48770693B48B615CE85C5C5335970 /* MBLOnDieTemperature0.h in Headers */ = {isa = PBXBuildFile; fileRef = 8738C2009B7045C579D0696C83A180A4 /* MBLOnDieTemperature0.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6A1D646998914294C2A425353C799D01 /* MBLAccelerometerMMA8452QFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = ECFC551F2CBA394E30DF1EE1AAFA3851 /* MBLAccelerometerMMA8452QFormat.m */; }; - 6AF54273822C94E2D534936CAB08A4E5 /* MBLAccelerometerBoschLowOrHighGEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E4339E9413CB51E88384FD2BB24A82 /* MBLAccelerometerBoschLowOrHighGEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6B2158F34E8AFBF2AF63C529AF6E1662 /* MBLExternalThermistor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0908E566C0DB4EF23AE31DF93476D076 /* MBLExternalThermistor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6B3471E60CC94FA3F906BD9CBCBF02BD /* MBLAccelerometer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2645876D1AD9695760FD68927753D24E /* MBLAccelerometer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6C91E3F5317327819188F3D00EC7B1CC /* MBLBarometer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CFBCFD2BF9FC802D2DF954EBFF6CBAF /* MBLBarometer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6CA88D78EDEBF118078D06712EE8C2F3 /* ColorPickerThumbView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4D3F620186E034F7C623B428D3109BD /* ColorPickerThumbView.swift */; }; - 6CD6A99F7035670F8297D8122D90102A /* MBLGravityFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = EDF27B3F155EBBF966F5A3073CC9FDB9 /* MBLGravityFormat.m */; }; - 6D1F8A96CF6E640CB79EEC7B33645EF6 /* MBLModuleMock.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD64C1100F3E64306313F24E970E06C /* MBLModuleMock.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6DCC7FF7294F8D0F2B15DC2298C05835 /* MBLAccelerometerBoschRMSFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 19C89EECF5C0B13F35AEEF99D8418005 /* MBLAccelerometerBoschRMSFormat.m */; }; - 6DF299FE058A9CE2D0970D006D2453D2 /* MBLAccelerometerBoschOrientationFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = C2E15C7CAF839B548FEC8915238371BE /* MBLAccelerometerBoschOrientationFormat.m */; }; - 6FDD6413C4975D6B93009C7F86E9FD33 /* FastCoding-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 374FAE1C230EFE649798C56C0E26D6E7 /* FastCoding-dummy.m */; }; - 708B5CAEC3C9689E4F1DD1FB01983ADF /* MBLTemperatureV1.m in Sources */ = {isa = PBXBuildFile; fileRef = 72290EA994E18E954E95E198E4CF8270 /* MBLTemperatureV1.m */; }; - 71416B3D101EB7B008EBFFEDD7829035 /* MBLDataProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 4519EAF79C77387F18804362AB896741 /* MBLDataProcessor.m */; }; - 7165B4A242D1918D7437E3C990225F4A /* MBLMagnetometerBMM150Format.h in Headers */ = {isa = PBXBuildFile; fileRef = B6E6F6428599AAF50B572B1FD082CE70 /* MBLMagnetometerBMM150Format.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7190F5456EAE7F0CEFE8427977F4CE73 /* MBLPhotometerTCS3472Format.h in Headers */ = {isa = PBXBuildFile; fileRef = DEFB1FF91118F26DC9B2C7DB3F183EAF /* MBLPhotometerTCS3472Format.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 71CA71FD244E8AB9B33C4FB32187669F /* FlexColorPicker-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1873C5BE50DCCCBECF6498A78492DFFC /* FlexColorPicker-dummy.m */; }; - 71E3FF46E57649D62DAEA5F88D8A4896 /* MBLExternalThermistor0.h in Headers */ = {isa = PBXBuildFile; fileRef = 2608EBF86FD05C8C65787DD976E8A7A3 /* MBLExternalThermistor0.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 727EB55637BBA5D63E9C71B19F6574D6 /* MBLGPIO+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C9E7AAB9EDEB14A11FC03AB7D891254 /* MBLGPIO+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 72D3DBA694CFA9FFFC3E4353F3F74214 /* MBLAccelerometerBoschAxisReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B069E8C2577A06891520F8052F65562 /* MBLAccelerometerBoschAxisReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 73BA62FB8D159A8A88B4263331AEC2E2 /* MBLPhotometerTCS3472.m in Sources */ = {isa = PBXBuildFile; fileRef = 97A9BB5093D62A978475C22DC60FBAAC /* MBLPhotometerTCS3472.m */; }; - 74024E47E558B9F4F86C0276248BF68C /* MBLSerial.h in Headers */ = {isa = PBXBuildFile; fileRef = 376008DE59AE2BE57F75A4D045ADCBDB /* MBLSerial.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 742F56778C738333597F6A15742614EE /* MBLDeviceLookup.m in Sources */ = {isa = PBXBuildFile; fileRef = 9719CDA5A212D1B94FE445E855713AE3 /* MBLDeviceLookup.m */; }; - 746969B5E2FFE91B27C98D9D4CE01AFC /* MBLAccelerometerShakeEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 09D173DEE35AC8F637F76E98BAA98367 /* MBLAccelerometerShakeEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7497AC4ECC997A66B500A88BC0B7818F /* MBLData.m in Sources */ = {isa = PBXBuildFile; fileRef = D263E60F84C555442F3EAF5B1A62319D /* MBLData.m */; }; - 7578004323F87F1A9D1F2A57A01772C5 /* MBLTestDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986B32117757A4EC70935FF197BF31 /* MBLTestDebug.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 75BF42D982E4A787DFC938A265C6DBE2 /* Bolts-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C6E172F7AFAEC647876724C2CDCD8E2 /* Bolts-dummy.m */; }; - 7646E03FE6A36C0187301C353AA6459F /* ComponentSliderControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = C596C5CF2FA47DB70CEEBD0155610BCA /* ComponentSliderControls.swift */; }; - 77563A5F471F5C1F6B3B40FFCA138892 /* PRTween.h in Headers */ = {isa = PBXBuildFile; fileRef = 6723B5F56E66FCC63A664969CF24F4DC /* PRTween.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 77DD698F6FC06A9B29DCD5CC6A3F8521 /* PaletteAwareScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47D66A0D6964C883FD711DA03207DC6F /* PaletteAwareScrollView.swift */; }; - 787102F95ED2B50406F8C0BC3BCD78BC /* BFTask.h in Headers */ = {isa = PBXBuildFile; fileRef = FD38F3710826BDB2D3C81503A2CFAD48 /* BFTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7966CBED14BE4CDB99874F067FA03BAC /* MBLGyroBMI160PackedDataReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 081C57DE88C04918BB9D408885753169 /* MBLGyroBMI160PackedDataReadyEvent.m */; }; - 7971E28FF50B61F003E3D3E1DE24D2C2 /* MBLConductanceData.h in Headers */ = {isa = PBXBuildFile; fileRef = 23907A2905EA3FA33DADE5E90FC69BED /* MBLConductanceData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7B029D89988C9741C1488653964B6C70 /* MBLLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = F3DB26DAB32F9C5F472F75CC5E362FC3 /* MBLLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7B81156F3AFD5D3B695E13405F508DF1 /* MBLEntityEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 12800A27E25D3F547A046667FE9DAA03 /* MBLEntityEvent.m */; }; - 7BB6A740AC730A49858F768945438686 /* MBLAccelerometerBoschTapEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 24D99B6BC6E29F9502C48BAB16605393 /* MBLAccelerometerBoschTapEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7CC030499CF261BEECAA968D4EC0AA3E /* MBLCategoryLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 532D7FCACBDEC3A993ACD5007C5C63B0 /* MBLCategoryLoader.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7CC91D5E3718E1E4C24D4C2D8D624568 /* MBLPhotometer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C228A5E96ACBA64A79B79955A47D11D /* MBLPhotometer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7CFD9927AAA45B33B4E745E262C23F00 /* MBLTestDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5D2835F778AEC4A8D236902ADAF29 /* MBLTestDebug.m */; }; - 7D6085C3E8DFCE88A4B15814DC64F268 /* BFCancellationTokenSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A6080F0AAC1DB95455EDE9EF02DBBAF7 /* BFCancellationTokenSource.m */; }; - 7DA57DF234CFD29BAAB6761211D22ABA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - 7E2B04696BAEDDCCB43948F773D855A8 /* FastCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = C7DC20CA8168B95E252E3D42883085AF /* FastCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7ECCE9FCCA33E7264FC83790FFB4783A /* MBLEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = A3D03AEC363BD828752113CECC7C80C6 /* MBLEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7ECCFD1030CB4F86DD2B3DC3A2788473 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8748CB4814020756E8C95D76D95C374A /* DateAndTimeFunctions.swift */; }; - 7FABE86421E53EC44D62B7CAB80BED09 /* MBLNumericFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 28D619B87C03D8885E04BDB6D3672B5B /* MBLNumericFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 7FD8E0630377995AB01E23C7CAE0BDDD /* MBLAccelerometerBoschLowOrHighGEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 49DA9CBC33AA2FDF6359C8FD3F306800 /* MBLAccelerometerBoschLowOrHighGEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8000EF1A3B7082727F948EFCD057BC3D /* MBLAccelerometerBMA255MotionEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = DD57F735FE5083BD26D4558A14334EE2 /* MBLAccelerometerBMA255MotionEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8068499A3E8EF7B85DA9E67272CD44CD /* MBLDownloadOnlyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B86A2EA02A200B150829527A34D0C29 /* MBLDownloadOnlyEvent.m */; }; - 815A632D16FECA82FC1D41D45BB5D1D1 /* MBLBluetoothPeripheralMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 81186E6794F9E16E132D1042A3A7382D /* MBLBluetoothPeripheralMock.m */; }; - 8175A97966E068EE204DA842337A1254 /* UIColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D7C3BE275BD60DCC89C7FD4F387EFF /* UIColorExtension.swift */; }; - 81A2D1DF71EE274A6DC7447C57FF9A4C /* MBLSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = D826EF23F09E0BE7A81DF628D497EE80 /* MBLSettings.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 81B744C4FC968FB189399EE1B8E27A35 /* MBLAccelerometerBoschFlatData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D69275F729CE8C895B6AEEB4E6E87236 /* MBLAccelerometerBoschFlatData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 81E336DB50FA13C2C3BE0CF75D825058 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3415A4F0C188A771B1C86C144FE2C83F /* Statement.swift */; }; - 81F7AD2B1301FFB9E0C7FDD58F49B306 /* MBLNeopixel+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 7FE83A6332BFB6ACF4D7F6098D332826 /* MBLNeopixel+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 82512AE61AB74A900DD786CDB9494594 /* MBLExternalThermistor.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C5799488BC7801B1D24372B47401F65 /* MBLExternalThermistor.m */; }; - 82FBB5309A78043862B74ABE56BB6274 /* UIImageViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 413CB9A1D4E013A9F23D12B5BC1A5D43 /* UIImageViewExtension.swift */; }; - 839D9CC4E54739EB4EFFC5B81A2A6D2E /* MBLStringData.h in Headers */ = {isa = PBXBuildFile; fileRef = F608D801CCBDDE5FA00277364777BE80 /* MBLStringData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 860E77BEA6D076A8D37A3C81DBE4E02E /* MBLQuaternionData.h in Headers */ = {isa = PBXBuildFile; fileRef = 4466877CF34DEA4079247DFB20452293 /* MBLQuaternionData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 868DE34BBEC92B602990B89F809BBBB0 /* MBLRegister+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C7516AC1991429F6A3B81EBCA1C708A3 /* MBLRegister+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 869D4F01EE7471735EEB2E3DE112A586 /* MBLDownloadOnlyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D25B6E79539085C97CB8B9387F181B8 /* MBLDownloadOnlyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8740838639CB0A07D62838C670E294F6 /* ColorPreviewWithHex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AC0F7FEF3F08355FCF20E99657DD8F /* ColorPreviewWithHex.swift */; }; - 878250824396973CC3136EB252DA7808 /* BFTask+MBLPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 654770BD0B9DFE0978C88E8FA6D5AE04 /* BFTask+MBLPrivate.m */; }; - 87D208C7E5C207583A0AFD7A3CBD22EF /* Bolts.m in Sources */ = {isa = PBXBuildFile; fileRef = 44B4B3FD98CDD35B0B752E3160CA04B3 /* Bolts.m */; }; - 87F9923DE5AA22BA7FF6EC67CF184D91 /* MBLAccelerometerOrientationEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 5B024B6DFDED940969EFF42A43655986 /* MBLAccelerometerOrientationEvent.m */; }; - 887203AE60FE7550F331465185ABA2B9 /* MBLAccelerometerBMI160.h in Headers */ = {isa = PBXBuildFile; fileRef = C034BDE0E58F942489EF132FFE65CF95 /* MBLAccelerometerBMI160.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8892EF77B05789AD6F6BC18D90AB8585 /* MBLCorrectedFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AE72B7641A8DE28BB231324BA8FA0C9 /* MBLCorrectedFormat.m */; }; - 89E907B9708FF15598D1A117D60BED53 /* Bolts.h in Headers */ = {isa = PBXBuildFile; fileRef = 917209A52726E7382B909C115B2A81F6 /* Bolts.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8B018EB5C72A9BBCE7518F98744DA0DE /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3900077A4790606E2800E23E5A2D5B1C /* Collation.swift */; }; - 8B30EA459330DBE023433AE07240587F /* MBLHygrometerBME280.h in Headers */ = {isa = PBXBuildFile; fileRef = CA5DE9F1D46C8C7DACC2C1C6A06C1C70 /* MBLHygrometerBME280.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8BA06EE3F00F3EB4918CAD7306D8CEF4 /* BFExecutor.m in Sources */ = {isa = PBXBuildFile; fileRef = D006A70806095AADD36919E07D16E88B /* BFExecutor.m */; }; - 8CF605AC994E3AB0AAF7A841C6E235E6 /* MBLHygrometer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D199B40598C2ED9D0CBE7BBB0823967 /* MBLHygrometer+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8DA3C6CF294542E420FBC089D70234F4 /* HSBColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D1777824CD3B762DAC2AFDF780D0A21 /* HSBColor.swift */; }; - 8DE2656207A57205A8096E85DC879A44 /* MBLNeopixelStrand.h in Headers */ = {isa = PBXBuildFile; fileRef = F598E2DEAEF60BBC882738F3C5DE09C4 /* MBLNeopixelStrand.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8E275DB6B02EC508FCCA47512A2A5BB5 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FE082C207AA18A150F1D2E98BBC37D /* Schema.swift */; }; - 8EAC37DD9A8F09AFAE51AAC1DB22B5B7 /* PRTweenTimingFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 177961493C41A3EA823992816120FAEE /* PRTweenTimingFunctions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8ECE7CB345AF9EAD0B6518AD7CDFA11B /* MBLLoggingV2.h in Headers */ = {isa = PBXBuildFile; fileRef = AB8E8A0E6C5761A0D832978E831F8B7E /* MBLLoggingV2.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8F0CEF19DCC1EBC96C119EBB51F0E69C /* MetaWear.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A521C64917321A402EE237FF16FD9B0 /* MetaWear.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8F5046755779521DD7851754F69CE072 /* MBLBluetoothPeripheral.h in Headers */ = {isa = PBXBuildFile; fileRef = E4BF4BB984F29F4878D167D143761F12 /* MBLBluetoothPeripheral.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8F79D376C0EE888418A6556C70FA9F5E /* MBLTriggeredRead.m in Sources */ = {isa = PBXBuildFile; fileRef = 821A25C88C6989010CF8A849993C7D4E /* MBLTriggeredRead.m */; }; - 8F93A34C71BC9E0DAB753F1989EA7421 /* MBLPhotometer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0131DF0EF949A15A0646568D00541439 /* MBLPhotometer.m */; }; - 9108610EF85A7D346E9726D5DF1A6933 /* MBLMagnetometerBMM150+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = AFB4497D5CD9672F5C95C767490B8BE1 /* MBLMagnetometerBMM150+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 91ACA3242477717D677C467C3D4EE04E /* MBLDataProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 66413B269210BA611B909CE76A0081F7 /* MBLDataProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 91F3FC606720D6E38438D3AC22E6877B /* MBLI2C.h in Headers */ = {isa = PBXBuildFile; fileRef = E5C4DDA6F69ECF8AEF12B4C8F399C412 /* MBLI2C.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9304E779EF93A87099DF87507B5E525A /* PaletteControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = B77B4FF4C17BA842D92B6BC68F66DCCD /* PaletteControls.swift */; }; - 93ABF8DBAE90FF09D36CC57F9BCFEF88 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 76BDD73914207FAFFF3E9CF5C71B1250 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.m */; }; - 93AF51ECF865332C7E9BAF670E370FC1 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E4CB215E9687C8D91C0023BBD18DEF0 /* Query.swift */; }; - 940A5DAF9BD33DBE9985BFD6807F52BC /* MBLMagnetometerBMM150.h in Headers */ = {isa = PBXBuildFile; fileRef = 145C4BA58ECB001DD5537B43D7365413 /* MBLMagnetometerBMM150.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 941FDF7E12A88B98C7587E283CACBDF4 /* MBLData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A80AAF5A16E49D99665CDBB7DB5F417 /* MBLData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 94394FC4BDE915844BC96B5FBD367B48 /* MBLGPIOData.m in Sources */ = {isa = PBXBuildFile; fileRef = EB90F9440DC08AE2F3B7D4D666F1C6A8 /* MBLGPIOData.m */; }; - 9455D90CA249F092044C5265B0E37916 /* MBLConductanceData.m in Sources */ = {isa = PBXBuildFile; fileRef = 79E7C3C9FA6588559703C398E7688432 /* MBLConductanceData.m */; }; - 9471CA8DA9878011E9D44B15F91A4BA0 /* MBLGyroData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 88A78BC9BED1903F288B99F8243780E3 /* MBLGyroData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 94D04C8948D2387D796EBE1AE39E6DEE /* MBLAccelerometerBMI160StepEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 857526C5F59A06EEAFB4093855DCF331 /* MBLAccelerometerBMI160StepEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 95007531A7D7167B8E2A934058E19D4B /* MBLAccelerometerOrientationEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 3518CBD6D03CE59AEF5ED8F8A1AAB9BE /* MBLAccelerometerOrientationEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 95355AF97A4A9D84DE7000A789301CA8 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EFA8BB36D6A79D6122BAADD7F82D3DC /* GradientView.swift */; }; - 95B164E33EC4430F4052E7AAB22DA85B /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC3480BE022D8E6D7401757ED8B81E47 /* CoreData.framework */; }; - 95F577F0286BE4F7FA035EFCE6262A0B /* MBLMagnetometerBMM150Format.m in Sources */ = {isa = PBXBuildFile; fileRef = 567F029623C3C2A10DC63BEC9ED354CA /* MBLMagnetometerBMM150Format.m */; }; - 9604CF7D4C4928BAFA81B3F8B5819F32 /* MBLConstants+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CA70F8707E848340FC61F67D2D09DA6C /* MBLConstants+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 96ED90E71125694BFDCC554BB5F68CC0 /* StaticDataTableViewController-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F19BA693EC7CE7E4E9C7B076C5F04974 /* StaticDataTableViewController-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 97418B166FBD270A593014C58AAED10A /* LimitedGestureCircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 465EF3F6218763ECC68FD764A9551DA5 /* LimitedGestureCircleView.swift */; }; - 97C0540DFD01F6C1485AD0E014821846 /* MBLModuleInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AFF5162AB9978EB3C44DC08A7021F3F /* MBLModuleInfo.m */; }; - 97F9C7DCFD0210D0AF29742C1336B914 /* MBLLED.h in Headers */ = {isa = PBXBuildFile; fileRef = 837BDA0EFF5B420C1734354EE59F809C /* MBLLED.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 984F476A550E339070B3ADD7C4C86B36 /* MBLNeopixelStrand+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DC7BB01B837D04C70825A8DAF533EF2F /* MBLNeopixelStrand+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 989F8569D8A349FF81DBF82E78BF19DE /* MBLProximityTSL2671.m in Sources */ = {isa = PBXBuildFile; fileRef = 47D7B95DD4B4EA43332240D4AFBC5C9B /* MBLProximityTSL2671.m */; }; - 98ACBC08142F99B0FE54A234B7EA8344 /* MBLTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 221760E26EFB265491A7EB9E276FA14F /* MBLTimer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 99042FD33B155F9606CB60A9D39A0F2D /* MBLMagnetometerBMM150.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FC26A49844C73557693D346B633ECF5 /* MBLMagnetometerBMM150.m */; }; - 99213BC3E73DB02EB2D188F075853AD6 /* MBLTimerEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = CCBB7805806FF294F5264BA8413A9B60 /* MBLTimerEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 99603D6C816D6502154D00E467A409CE /* MBLMockUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 48B07B0B83A11EC07DF4B3E6582A952A /* MBLMockUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9AB1CF400245D7B0CB2901240D0D8A47 /* MBLExternalThermistor1.m in Sources */ = {isa = PBXBuildFile; fileRef = FE35C2B58564FC49CA69375A23CB33E0 /* MBLExternalThermistor1.m */; }; - 9B246E73DAF18E3BCE7B1F75D3CBEBAC /* MBLPhotometerTCS3472.h in Headers */ = {isa = PBXBuildFile; fileRef = E091FF5FCF34D77B3F81C5E20BCD9DDA /* MBLPhotometerTCS3472.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9BD4469FACF1754518D884524C7FC482 /* MBLTemperature+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DE60CA9A1403AB574CE630E92B1D9A87 /* MBLTemperature+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C490FA55D8BA12069809F6A90134B09 /* MBLAccelerometerBoschFlatEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F80F0FF6C6D5436494E3102489E662BE /* MBLAccelerometerBoschFlatEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C9177A9F9FE48904009162459EAF98B /* MBLAccelerometerAxisReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 92D515E4EBB8012585D33EBE80ABDE75 /* MBLAccelerometerAxisReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9CE445FA94FCD69779725FA2440A6FD8 /* AdjustedHitBoxColorControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 427AC7DC4569033439CABA2A30EC3326 /* AdjustedHitBoxColorControl.swift */; }; - 9D1330DC67167B9BE31E129E9DAA5717 /* ColorPaletteDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C65A26A196DDDE0F69C776EA4C8AD4CD /* ColorPaletteDelegate.swift */; }; - 9E31D1EE91E56CC69F7F927F2AFD2BCF /* MBLAccelerometerBoschPackedDataReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 74CC7720DE0EECC6FADF0ADA2BBB29BA /* MBLAccelerometerBoschPackedDataReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9F180A87AEEE03366E3C6E4A673799AD /* MBLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A0C1066A28DFD968093094A4002CDC2 /* MBLConversion.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9F53304512F490377492AA1C45139C04 /* MBLNeopixel.h in Headers */ = {isa = PBXBuildFile; fileRef = CE782EDB13AAB2925552025E053F7928 /* MBLNeopixel.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9F9C97200E884E5D0E8C6380EB33F10C /* MBLMetaWear+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 820C5930C99368E34D4BA3FF59AB6DC8 /* MBLMetaWear+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A1C9242CA4B22CB221EFEDF026EF6C5B /* MBLCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = D432760CFB31355CF1D7A1ED92629E19 /* MBLCommand.m */; }; - A25241523D536543ECD771590FBA3FE3 /* MBLMacro.m in Sources */ = {isa = PBXBuildFile; fileRef = E8C10FD0F6E850F0512408F4C54A7DDD /* MBLMacro.m */; }; - A26CA6C72D232E8BA4B61356584B56E3 /* MBLFirmwareBuild.m in Sources */ = {isa = PBXBuildFile; fileRef = A5DBB6C06E3DAB5CC269D3472516F20C /* MBLFirmwareBuild.m */; }; - A2D30CF69D06FCBDD0E0C56057855FA3 /* MBLRGBData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D552F19EA6C6A6E324AD9F25F1386347 /* MBLRGBData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A2F14B12F347667B99ADE221F3C55C10 /* MBLAccelerometerBoschAxisReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 314B0529C31F19362B7AD83D00A099B7 /* MBLAccelerometerBoschAxisReadyEvent.m */; }; - A3DA1CDE4325738D463013CBEC8AF645 /* MBLAccelerometerBMI160MotionEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 1292C8E610760DB6D2DAF8A9F2109BDE /* MBLAccelerometerBMI160MotionEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A4363ECC3F8EA39A4FE0D8A84DABC6E0 /* CircleShapedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70662CA035EC8936750C436C9EEA15B8 /* CircleShapedView.swift */; }; - A4A79DFC8B12396BC9400E1D614EF112 /* MBLGravityFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = B1CD72E1EDED538FB7F734E6A318EEF1 /* MBLGravityFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A4CBDE2B1DFCCBB9795F8142C739B836 /* ControlWithThumbView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D786128F75597E6534D0A3DE85100713 /* ControlWithThumbView.swift */; }; - A4FDC30E169690FDF1137D3E484D6567 /* MBLAccelerometerTapEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BD01F654DE5D06ED7C89636CDE53A98 /* MBLAccelerometerTapEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A53B216BEF75D7D7D35FF44476620BD5 /* MBLNeopixel.m in Sources */ = {isa = PBXBuildFile; fileRef = DBC2489879DB2FD6A78ABBAA6A302EDD /* MBLNeopixel.m */; }; - A6CB154A32BC7042285BB8C97FA9E5F0 /* MBLRegister.m in Sources */ = {isa = PBXBuildFile; fileRef = FC52BBDAC51F31E80A57E1857CF0AE49 /* MBLRegister.m */; }; - A77115FEBD116A1E840ABB370B12CD60 /* MBLAccelerometerBoschOrientationFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 51983FC1E94C3A7B3263DD06D3CCB519 /* MBLAccelerometerBoschOrientationFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - A8679588CD4819BB74A49D2006658252 /* MBLLoggingV2.m in Sources */ = {isa = PBXBuildFile; fileRef = 8201272484180FA4D05CA43D01CE4B97 /* MBLLoggingV2.m */; }; - A880766B4EEF078F97BA8E3FF5BDC6B0 /* MBLFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 79DAF916659E8B5554A2381CE21AEABA /* MBLFilter.m */; }; - A90332024C9411863217799521D89900 /* ColorSliderControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DEE8A761E6F3EFD39AC435300060A92 /* ColorSliderControl.swift */; }; - AA068FACD628B4D9F72DA0B5294F8F8F /* FlexColorPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D957451FBD0710F6B80E2099435B1C6 /* FlexColorPicker.h */; settings = {ATTRIBUTES = (Public, ); }; }; - AB240671C15F1E8759FE431FCDB34FF2 /* ColorPaletteControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 246B555E509917B4C8FE7D6D29CDD369 /* ColorPaletteControl.swift */; }; - AB59BEE6A9C358955FC2F2569C641CF0 /* MBLConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 67ABBB9175C1AB274D0D7EAA75F73CE3 /* MBLConstants.m */; }; - AB9EDE885EB28B940082A14083F6CB4C /* MBLiBeacon.h in Headers */ = {isa = PBXBuildFile; fileRef = F8B642B6E984F380366552C1C3AB5752 /* MBLiBeacon.h */; settings = {ATTRIBUTES = (Public, ); }; }; - ABCDA56D252176659A1A1D9BFDD726D7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - AC178C8BC13F6BB812CF480DB5DF74CE /* FlexColorPicker-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = D329E9BD6CF1B08F9C596B19BA5717D0 /* FlexColorPicker-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - AC681AA08911682051FC6AD79308EDA5 /* MBLDeviceInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F8E304B92A2F672CC202EDC0422B1E9 /* MBLDeviceInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; - AD3FFB62B0671B9D701C82E400B518AF /* MBLAccelerometerPackedDataReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F903D70AD9EE4E936590A1F2EC246AAC /* MBLAccelerometerPackedDataReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - AD51632D719A7A4FF25F29E6F7AA2288 /* BFTask+MBLExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = F008509C008A129206D0F8D7A25F0F74 /* BFTask+MBLExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - ADE7562DAC780E8A80885053A6053212 /* MBLRMSAccelerometerData.m in Sources */ = {isa = PBXBuildFile; fileRef = 3754406911E8EE9E7F3A41663E738787 /* MBLRMSAccelerometerData.m */; }; - AE509515FB5C6503228AA70CC68FE759 /* PRTween-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CC217CF9EA007AD52303A46616501F0 /* PRTween-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - AE970A3D760E50E6DEC90A85713B9CCC /* MBLAmbientLightLTR329.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C8F2D1B54544E1C5892E95341D19CB9 /* MBLAmbientLightLTR329.m */; }; - AEA04AFE9100BC69D24A526F9A22CC74 /* MBLGyroBMI160AxisReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = ADB19BA4C93D3926CE12B4649B33E5FE /* MBLGyroBMI160AxisReadyEvent.m */; }; - AEF0B65B1B2CD43D2F74C2AF8909FF0D /* MBLFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = FD5F594EA2EE25FD89526C65F52CEC13 /* MBLFormat.m */; }; - AFAC1D4EBD53A048346210536741DF13 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1F094F5014C64256F003CA4D7015EEB /* CoreGraphics.framework */; }; - B07A78B35592EF6032FAE5A46F17DBF8 /* BFTask+MBLPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = FD3580AA05CE67ED12CEDA2573B69C33 /* BFTask+MBLPrivate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B083234300A1D900612C5CDE2B681CCF /* MBLAccelerometerBMA255+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A6FFF11EC07CE95E9550644682930EE /* MBLAccelerometerBMA255+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B0A17D93DEC37FBFEE2DD5870951785D /* MBLAccelerometerBMA255.m in Sources */ = {isa = PBXBuildFile; fileRef = 25FA6D0F03DE44901187E3563AD33707 /* MBLAccelerometerBMA255.m */; }; - B0CCBA3FA4406129F1F409598E85045D /* MBLMacAddressFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = EBDAB5AEEC34E895F148807F2B35FEA1 /* MBLMacAddressFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B16A40603362F6B7A6252136C019AF07 /* MBLBarometerBosch.m in Sources */ = {isa = PBXBuildFile; fileRef = 73950693CB69C144751AB0335D5AF000 /* MBLBarometerBosch.m */; }; - B1F915ADA0E5011C8B6FD1590BB17779 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5ABAB1C2F3A3165F73F7E8EB46EDD41 /* Operators.swift */; }; - B299707DAB665E5C20B8A1A10C4BD342 /* MBLAccelerometerBoschOrientationEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = FF55FC4FE71555887D78514BC4977D65 /* MBLAccelerometerBoschOrientationEvent.m */; }; - B2E884D979703A70ABAEB807118667B0 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C1C7FC4D76208F93B744123BD11F49 /* Value.swift */; }; - B44D91A49063DD48F3EAAF4AFEEC8783 /* MBLAccelerometerMMA8452Q.m in Sources */ = {isa = PBXBuildFile; fileRef = 68DEBCDB3540DF8E8A66FBD60AA6EC1D /* MBLAccelerometerMMA8452Q.m */; }; - B52177FF72FDAC3EDB7195DE98F5501E /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E946D77D182D19C59CE1B9781394E3E5 /* QuartzCore.framework */; }; - B59AD511EECEBAE1A6896FFAC0F956CD /* MBLANCSEventData.m in Sources */ = {isa = PBXBuildFile; fileRef = 5593CCBED8E4AE15625FF3ACD2A666C7 /* MBLANCSEventData.m */; }; - B59CF6F64C1DA915D1E780479BACFFDE /* MBLAccelerometerPackedDataReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = B134A1DB88245EF935E2BC1D6B053A2B /* MBLAccelerometerPackedDataReadyEvent.m */; }; - B64014FFD36F38A0A273A5A065FE7F15 /* MBLOrientationData.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F276868A47C5827372AA153634270CD /* MBLOrientationData.m */; }; - B6BAFAFFBA7FD1CF919F4964B7B68C89 /* MBLAccelerometerBoschOrientationEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A32380E9FDE7BF474147BE27EF6EA33 /* MBLAccelerometerBoschOrientationEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B72A378B5FA47A57E69BCEF5FEA70E92 /* MBLEntityEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35847D051FF4AC1EA26B080D0C468C99 /* MBLEntityEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B79DA90754CBBA0513569A6F5E3C3C00 /* MBLEntityModule+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D1DC59226A6BE4F5117B51F1D275E92C /* MBLEntityModule+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - B86419765F5D00C53B7DAEC72EA8DD8D /* UIViewWithCommonInit.swift in Sources */ = {isa = PBXBuildFile; fileRef = D89AED1CFA1E87CC33F977C4257D8921 /* UIViewWithCommonInit.swift */; }; - B9B8A4F1B99AE2827D8F87354994E16F /* MBLAccelerometerBoschDataReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = AC09702064EE3145D24A7F67CEC32E08 /* MBLAccelerometerBoschDataReadyEvent.m */; }; - BA81DFE0ECEC3454B415644491BB9559 /* BFTaskCompletionSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 38AFE3A959AC36D6E49E405E5F9C6B1C /* BFTaskCompletionSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BB765876090DBA0C76F7EB8D7BD4DE61 /* MBLDependentData.h in Headers */ = {isa = PBXBuildFile; fileRef = 5865681E3AF1BA1C5A344C7FAEADCD6E /* MBLDependentData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BB9BAE65895E2A87EF650E43306262A4 /* MBLRegister.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DC7BF0532FFB6F12EAF271B32F7DF12 /* MBLRegister.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BC64B743E0E8A66ED93B5609D3325CDF /* MBLModule+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D80477684FAEDE04B68CA136E5D1FC6F /* MBLModule+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - BCB035BFC809F5A092499DFE9319E967 /* AbstractColorControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CE957C206AFAC66F176C3FF5B9495C7 /* AbstractColorControl.swift */; }; - BD3B53AE09FC635515D7E8669A876A34 /* MBLDispatchQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 8626A34A32F4E09F7180102BDA29423B /* MBLDispatchQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C0A90325A2E7C8B558B3B4D7C13BC2B4 /* MBLI2CData.h in Headers */ = {isa = PBXBuildFile; fileRef = 7965DF8D05996851B19C61D851F9D1D0 /* MBLI2CData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C0C33C48226D2F294414E397B700D3F7 /* MBLEulerAngleData.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D4398BE85C107FC9E87B95339D7DECD /* MBLEulerAngleData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C0E08E3F92F4FD10789F379EFCB2D0C4 /* RadialHSBPaletteDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA113996186396182E6481062F4AA736 /* RadialHSBPaletteDelegate.swift */; }; - C2896E99CF6C700E0CFC00B11CFFC0E4 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E217536EBC923746AA9E13572B239634 /* UIImageExtension.swift */; }; - C2D5A24514DAE62B1EF5E13515CF486A /* MBLAccelerometerBMA255.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F71375DD28767C26672DFD841B1BE72 /* MBLAccelerometerBMA255.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33C9FF48D09DAC9817823DD802DF6EE /* MBLSPIData.h in Headers */ = {isa = PBXBuildFile; fileRef = 38F0F7A8A8D5D19437156CA5EE554129 /* MBLSPIData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C36D7D51D5F496C1FCA1968B8DAFBAB2 /* MBLTemperatureV1.h in Headers */ = {isa = PBXBuildFile; fileRef = AA41C9AFBA1DEDF1DB28131ED13B1416 /* MBLTemperatureV1.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C3A54BCAFE3C26E876B0748AE7EC1FE7 /* MBLANCSEventData.h in Headers */ = {isa = PBXBuildFile; fileRef = A4397048407923C022BF6296206C83C2 /* MBLANCSEventData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C58610A0A7F45490156BD2A2B485F965 /* MBLAccelerometerDataReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = B60A4C304F52AA1358CD318BF8438FF7 /* MBLAccelerometerDataReadyEvent.m */; }; - C5CE3E1392D6B8B6CBC812E08A461F4A /* mma8452q.h in Headers */ = {isa = PBXBuildFile; fileRef = 38CFCDB0514EBAAEF4CEE12D05EE8109 /* mma8452q.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C5DEA8D620EA6295CD81B9E0DC349402 /* MBLModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BF96EFA28DB351EBE7678639DBEEE959 /* MBLModule.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C6316CBFF2CE41DB8CC35E2D9F92A183 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E9EBD3665678A28C911C3EC04616F63 /* SQLite-Bridging.m */; }; - C6B218A24D2655E817143B75F2AE6239 /* MBLSensorFusion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F164C3F15CFB0FD52FD5C684DCE5CE9 /* MBLSensorFusion.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C75EC2FDE5619D3F7393E4A5B4D4DAF6 /* MBLDeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = C36BCB63685C8F467D7666E915B25FE1 /* MBLDeviceInfo.m */; }; - C78DD531D7ADDE389D58AC90CD163FFB /* MBLLoggingV1.h in Headers */ = {isa = PBXBuildFile; fileRef = 177E694248790CEB1B03BC3481CFED6D /* MBLLoggingV1.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C8E49F832BA4CDACBB754F207B889EE6 /* MBLMagnetometer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C8165089578A149C045394501D28749 /* MBLMagnetometer+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C8FA535E3E3CA00982B7050BEDDE0786 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - CA566D69FF3773754415A22C9A5E9EAF /* MBLMagnetometerData.h in Headers */ = {isa = PBXBuildFile; fileRef = 55E0C2D944995BB40CFA9BD4DF56E8EC /* MBLMagnetometerData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CAD31E80D4FA4D955FC986A4B8B7E68A /* MBLFirmwareUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 897B8CDE723F546E2116F984DF33DF5C /* MBLFirmwareUpdateManager.m */; }; - CE5067B38ACA71E582DF300E3DCD7372 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - CF0447DDC959205BCFB42B4EB655645B /* MBLAccelerometerBoschTapEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = F767D6AABF23900614BC7666848C7158 /* MBLAccelerometerBoschTapEvent.m */; }; - CF3B9128DBFEB8241563931619B8E7FF /* MBLModuleInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 74B21379AD8E4BA85136D6EA4099C510 /* MBLModuleInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D007F5D7DF6E5D1976DAE4395DBA71D6 /* MBLEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 80177AF5756ECF16947D8BC3FB15DA32 /* MBLEvent.m */; }; - D10A4C1E78E0103E99AF753A4F9D47E4 /* MBLDataSwitch.h in Headers */ = {isa = PBXBuildFile; fileRef = BC01372E68FAF8353E6B5FF3C839FE55 /* MBLDataSwitch.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D1285DA4503F99A14C1CECBE71E0AF03 /* MBLDispatchQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D4A3E8010251664FDF4E101B79FE66C9 /* MBLDispatchQueue.m */; }; - D12E81F7891DD3DAA4A2CDEF773B49FD /* MBLAccelerometerBoschFlatData.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FC5822E40E89D5C92D574C41A031395 /* MBLAccelerometerBoschFlatData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D1DCAEB4F311D177D6C27826B82BDB95 /* BFTask+Exceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 314B82F710899A1A23F5558B1E07BC30 /* BFTask+Exceptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D212A71052A618EA16A6EE2902DB449E /* MBLAccelerometerBMI160MotionEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D812B690E5B0D2F8F5F6CAE1E33FB56 /* MBLAccelerometerBMI160MotionEvent.m */; }; - D24328ED34ACC9B1543D1B9A3A8A4869 /* BFTask.m in Sources */ = {isa = PBXBuildFile; fileRef = A75EEDEF0F8BD9F3DB6E1D7268D8C0E3 /* BFTask.m */; }; - D255A7BE82C7FDFF215DA9BC9E7D12EA /* MBLNumericFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 15DEFC6322F383667D9163F4CA090C54 /* MBLNumericFormatter.m */; }; - D31047011224F20FFD53626316AA8FF8 /* MBLMockUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 76E454A82BFF17A592A4B90B73930D61 /* MBLMockUtils.m */; }; - D434753461729257C4F2C0E765F95955 /* MBLHygrometer.m in Sources */ = {isa = PBXBuildFile; fileRef = E7FB521DBD6D8988829ADAF5B7745088 /* MBLHygrometer.m */; }; - D6C8986CBE92ABAE5156BBF2D344336F /* MBLAccelerometerShakeEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AEF8FF9DDA0EA639C8A63DF8F3EAD02 /* MBLAccelerometerShakeEvent.m */; }; - D7277DD485764C26A4CC92D429A10882 /* MBLAnonymousEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = A6D37657F3EE943952978BAB8DA03E58 /* MBLAnonymousEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D7A26AD0A8698181B4CABEF0CC48168C /* MBLAnonymousEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AA5616E4E4280DA16737BF116DD49F6 /* MBLAnonymousEvent.m */; }; - D80AA1B238162FA2B61ACE9F4F4BBC3C /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5F91787B75837730129E0136066D012 /* RTree.swift */; }; - D9F21A635BAA8BB36A68B88DFE16C6EE /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2AF51A650223D1BB2740F2372BE7090 /* Blob.swift */; }; - DA6409688B75D28260A57FCCD28AE71F /* MBLBluetoothCentralMock.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A83AECEA017C91C9F5CBA32F375B09E /* MBLBluetoothCentralMock.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DB3AC10325C65DD276844A4DA56C5930 /* MBLMovingAverage.h in Headers */ = {isa = PBXBuildFile; fileRef = E1C3A991414ED39811546573DA275F5E /* MBLMovingAverage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DB604C3949DB26DDCA99622F1D4DD31F /* MBLAccelerometerBoschFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C15691C1FD31BFF5F8FAFD44482CA17 /* MBLAccelerometerBoschFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DBC29BC4541E4385BC95E162358E0779 /* MBLEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CFD114275AF87D35C2037EFF0F9B077C /* MBLEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DCB43723E364DB6788C3BAF8ED99FC5E /* MBLLED+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 832E6B3B6A39524018A87DF2CB10161D /* MBLLED+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DD5561CCF8DAAB73DC865462498DD77F /* MBLAnonymousEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D900690513FC59CD201C4FEC888AB9B /* MBLAnonymousEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DD96B7D6D05C6CD7F3C68DA5190965AD /* MBLDataSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = FE6D1D6FC47BBB89650B9555D22855C7 /* MBLDataSwitch.m */; }; - DDEBCDA02E20A072F33257C605102AB0 /* MBLTemperatureV0.m in Sources */ = {isa = PBXBuildFile; fileRef = 448ECF74A645B4FA12173EB17977FD37 /* MBLTemperatureV0.m */; }; - DE24ACA4B2C8E66BE111A04B8949425C /* MBLAccelerometerFreeFallEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = FE708F2E2F9A1E68737F97B4C29E57FD /* MBLAccelerometerFreeFallEvent.m */; }; - DF1D172F1BE8BBE268AD9ED807E78970 /* MBLAmbientLight.m in Sources */ = {isa = PBXBuildFile; fileRef = FECF0D6201B0367E4A4A6B183BDC70A5 /* MBLAmbientLight.m */; }; - DFB4BE1BDE7704075922033B431F3660 /* MBLAccelerometer.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1B6E114D5CB12C862036963DCB2390 /* MBLAccelerometer.m */; }; - E0B99E76EE958678464B38396A04D90A /* MBLHygrometer.h in Headers */ = {isa = PBXBuildFile; fileRef = ABF926A861C75B028D5DEEAA25BBED22 /* MBLHygrometer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E1D953B9AADC002F4CB917B32C67967D /* MBLHapticBuzzer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8060AB9A8C984249C5C707878D88D5EC /* MBLHapticBuzzer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E1FADA244CD8C6C19DCBAB65F95F8A97 /* MBLMagnetometerData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E1E7DEA33754A4BDE312E7F9208C89F /* MBLMagnetometerData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E20FB97E7825A9F5BB5B2E35966F9459 /* BFCancellationTokenRegistration.m in Sources */ = {isa = PBXBuildFile; fileRef = A0C072E7EBB31D497A02922D12FFD0BF /* BFCancellationTokenRegistration.m */; }; - E21E851F3D9F8F51D7A868DC560429A8 /* MBLGPIOPinChangeEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 689DA3C1690AA04AD8F0B525102106FB /* MBLGPIOPinChangeEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E2890E4DEF6E67952436180636C81064 /* Pods-MusicalCaneGame-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 448E2B4D025708620E619D128E766E36 /* Pods-MusicalCaneGame-dummy.m */; }; - E30E3081D2C9E72DDB1C1DC7573FE3BD /* MBLGyroBMI160Format.m in Sources */ = {isa = PBXBuildFile; fileRef = E5F60FD4BCF56BE7DBDA9F7FFB76CED9 /* MBLGyroBMI160Format.m */; }; - E352E7D4C9D3E2A731153221B88921BB /* MBLFilter+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B61285A50EC5FE9ABE7406F805BD7ED /* MBLFilter+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E429436B0DFEBCD3B38A92D86B128224 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */; }; - E4C649663E1F2050333323689070E9B4 /* MBLGyroBMI160PackedDataReadyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 39D64BE10B561A0D34719CA9330EB32E /* MBLGyroBMI160PackedDataReadyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E4D7303B5F927BB34DB1DE592239C6A8 /* MBLTemperature.h in Headers */ = {isa = PBXBuildFile; fileRef = A1B3444495ED8736F3DFC544DA9D9F22 /* MBLTemperature.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E52F5B8CBD021B21220129C3597146D6 /* MBLConductance.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C073299F231C20AA958CCE9BE21E29B /* MBLConductance.m */; }; - E5CAA737AE8493EB95A4DB3EDDA9B33E /* MBLModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 72F8368AD145B7E0B2F4F356CD3EF20C /* MBLModule.m */; }; - E5E70C681E75372DA36E22210441B9E3 /* MBLSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E0C59754C9E2B1A128BA2D4C6A24D4 /* MBLSettings.m */; }; - E60FF3CD3C3032931BF9D35AE8EE18FC /* MBLAccelerometerBoschPackedDataReadyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = E8F7A7C727EEC2172412B3E86EBA2AEF /* MBLAccelerometerBoschPackedDataReadyEvent.m */; }; - E635AFF0EA9CF2A025035B1743C4AFE9 /* MBLQuaternionFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 2754222A4444878B4FE2DFA4619E1593 /* MBLQuaternionFormat.m */; }; - E75B43A0CE1D24F53CD568AF709EB23B /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0181593C309048FF98276EB66B259494 /* Errors.swift */; }; - E77FAE2B61E1FC76DDF18C5FF69EB52F /* MBLAccelerometerData.m in Sources */ = {isa = PBXBuildFile; fileRef = DEF9607D057EEFF22A1079E9E3ACF6CB /* MBLAccelerometerData.m */; }; - E81A68AC1FE467D049830BEBB84666F6 /* MBLAccelerometerBosch+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = E2DFA2FD74F0EF2EB5D0CDA3A3B98463 /* MBLAccelerometerBosch+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EAE0C24ACB689B64AC07E30A7B90506F /* MBLAccelerometerFreeFallEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = A40DCE98EAF323F2D77DBC24BEA5D411 /* MBLAccelerometerFreeFallEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EC15485522F94A0B4F7BD64A8592BE82 /* MBLProximity.m in Sources */ = {isa = PBXBuildFile; fileRef = 462DD61F30926FABAAD6EA3D27791201 /* MBLProximity.m */; }; - ED14B2DCB2151BDE96F3B95A1B6199C4 /* MBLANCSEventData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 396C92EDB59F8462AA3C5CF4A773E86A /* MBLANCSEventData+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - ED881C93A86D1B03630F20381EC0CCA5 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 50B863789CB70C7BB079677C237AD2B1 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EE5C34446DAACC83AEFBF004F31D535E /* BFCancellationTokenSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DD12BA668FAAE372DD539EC9C82734C /* BFCancellationTokenSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EF12270B12F496C08630137D7B227072 /* MBLModuleMock.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E6328E370911FF7407A878B58FBE742 /* MBLModuleMock.m */; }; - EF2F05C845EF1AEE3585FB4436352D52 /* MBLAccelerometerBMI160+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = D340450AACFCF8501E977E327B72295E /* MBLAccelerometerBMI160+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - EF7C980431AF65A6BA0E612F4D92A4AD /* MBLAccelerometerBosch.m in Sources */ = {isa = PBXBuildFile; fileRef = B6E391DFCD4A71DF7EA3A6D8477D386B /* MBLAccelerometerBosch.m */; }; - EF839C7C1F3D490E0D803222BBECA6AD /* FastCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F3FB7312B0FB66FA2194029BF866463 /* FastCoder.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - F071B79A43AF6FCFDB0BEFBD80DF0662 /* MBLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 80EF906667CF40840440B6176DB8E974 /* MBLLogger.m */; }; - F0DD090C2F438F7D454504613A8AC5B2 /* MBLNonVolatileState.h in Headers */ = {isa = PBXBuildFile; fileRef = 7114D8A31D2986FB66EF6D7AE023531B /* MBLNonVolatileState.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F135C9FE51E500398FCAF3183359338C /* MBLNumericData.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C1E3DBB7FF2A60BFDBFDCED8736F8C7 /* MBLNumericData.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F19E5EBCE21503E50F1443658CDE1221 /* MBLAccelerometerBoschFlatFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B3A9FC030CAA3A37E8B12FB7E4DDA76 /* MBLAccelerometerBoschFlatFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F337804A9799941C65D95D42EBD6277F /* MBLAmbientLight+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B42FA1179121C2BACE59FD1E5CCD9D15 /* MBLAmbientLight+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F346385538DC01D7451F3C8D5580E2C5 /* MBLAccelerometerBMI160MotionEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BE81BC86D60BB954223F36E9EBADEB9C /* MBLAccelerometerBMI160MotionEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F34EDB8535E392FFB6CA369128586840 /* MBLProximityTSL2671.h in Headers */ = {isa = PBXBuildFile; fileRef = CAF56CC7BF0723A62B749CD5DF597DB7 /* MBLProximityTSL2671.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F3CD6B4A5B51B4CEDAD4D7718A696608 /* MBLMacro.h in Headers */ = {isa = PBXBuildFile; fileRef = 89E9AD6A613937C723DAE21265CF0A32 /* MBLMacro.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F47ADF6F6C2B9137A8972E40AD2D2C29 /* CustomColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C74601C377948832E851B19266E34DC4 /* CustomColorPickerViewController.swift */; }; - F500F62E9EA41D3BF7760442DD8DAD93 /* MBLGyroBMI160.m in Sources */ = {isa = PBXBuildFile; fileRef = BEC5AC5CB64ED4E1F0FFADAA163F3A2F /* MBLGyroBMI160.m */; }; - F5A65785CD828CC0E12B4AD0E9686FF9 /* MBLAccelerometerBoschTapEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 8FED6CFDFA4AED3BC7EDB54252A9B78C /* MBLAccelerometerBoschTapEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F61DB9A5C99B33D0A9BADE7858F81EBD /* MBLSettings+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = AD10C0FA17E34B86E7160A70689FBC3C /* MBLSettings+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F6B763D2AEAF6E413FD4D997E396CF2D /* MBLQuaternionFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = F32D36EE8FB83CE82EF6360F883DFBC1 /* MBLQuaternionFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; - F7C5C28ADE72BB800E9E39305D0F4E55 /* MBLQuaternionData.m in Sources */ = {isa = PBXBuildFile; fileRef = 355BD6A3989345E5BAE24648E1B93CA0 /* MBLQuaternionData.m */; }; - F84C73866CEE373D62DF36A6AB652C55 /* MBLAccelerometerBMI160.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A837EA4F931F8F22DB23E84BA700143 /* MBLAccelerometerBMI160.m */; }; - F8CBBEB30F91DD5D67775AE2BB500709 /* MBLAccelerometerBMI160StepEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 2BE3ABA4E60E29199045F2A64CD74F91 /* MBLAccelerometerBMI160StepEvent.m */; }; - FA2CAF4E18084BB84CF1087AF8AE8385 /* bmi160.h in Headers */ = {isa = PBXBuildFile; fileRef = E6D0EB9A44103CC978560C08DA0B7308 /* bmi160.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FA4165C30F007120A0061D64985A1C3E /* CGRectExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A1ADBF675F2197D8BDC63EFAB0173CB /* CGRectExtension.swift */; }; - FA522FEAA890D4F8BB7ABBE5ECC5EACB /* MBLSensorFusion+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A6F4150D266A40B8F330513CCE21781 /* MBLSensorFusion+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FA7A067DA6BF6A3A00E0E0FB148319EF /* MBLTimerEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BF08C236AA2798EE30C42E2EED2C4F1A /* MBLTimerEvent+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FA90AA80C6FD95C594DFD4955C3EA556 /* ColorSliderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6719B0DAAFC53A5D67AB989C9C97A924 /* ColorSliderDelegate.swift */; }; - FB078FCB95EF6D4F5F6B063F953E40ED /* MBLMovingAverage.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B842C1CF9D05CBEB663920D19E57722 /* MBLMovingAverage.m */; }; - FC41A374495D394E691F3F96A64128F9 /* MBLCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 0035D91A4EFD0627194FE64A3B48F79F /* MBLCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FCB139CFF9D146093A70F4281888B15D /* FastCoding-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B125C22BB5BB7A4B5211815B2C948FF4 /* FastCoding-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FCDB25BAC24D043C17317C7289249096 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA0C8F987AE0F0506C0177F097AAFF2 /* AggregateFunctions.swift */; }; - FCE5E614A5F6D50D8C24CA228507BB20 /* MBLAccelerometerBosch.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E6A9A89A7A6D2068DA309A57810A3F3 /* MBLAccelerometerBosch.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FDA89C4D6465835B38D1BEA06158B884 /* MBLConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AEF92ED6E230F7C4BE4000DC9B2F37F /* MBLConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FEB46AF0929D4D9D68B98E1D8F7F2ED0 /* MBLMagnetometer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AF74140BE838529FCBE559FF49324FE /* MBLMagnetometer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FEBCCC4E19AA5490CDF85FCB85AF2EF0 /* MBLProximity+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = FF21E26B641B2F5997E7D0DB7EFD730B /* MBLProximity+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FF9FC0893F64401D9EC5702DB7DEE54F /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73446BDE690FF38C64E2D46A9E471DA0 /* CoreBluetooth.framework */; }; + 0097064E7F7D3F413161738CC5C25EEC /* MBProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 93819BB5AB4610BFDF6F0FC2282E4DDE /* MBProgressHUD.m */; }; + 00A07184BA261FC0F9E7A941DE025FD1 /* SQLite.swift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = FDDBDDC69CDAD4981A3821042DABE063 /* SQLite.swift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 04295D7285B17C002ABF746D836E97FF /* DefaultColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 922596DF6C398433B0444D3BB469CE7C /* DefaultColorPickerViewController.swift */; }; + 045BBA23F6CFD80FF1558F1091A8D297 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */; }; + 04EDF2F6371D812E267BAC4F8E9A6433 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */; }; + 087C7310465DE213F5EB5A3EBB437AA3 /* SQLite-Bridging.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C81353C57A838AFF0848801B54CC23 /* SQLite-Bridging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 090DCCF33882E1EC2ACD0B10CE7A6D24 /* timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1117B4651FA1A8584AA3B198D1592A04 /* timer.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 0AA33EBB857A5205F87C09CCB99EAC74 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */; }; + 0BA10E7421D5BCF6526536185D556375 /* Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBFD3354E9C426820E89DEB251A57B3A /* Connection.swift */; }; + 0BB000DC3091D0547F99099882EF4BB6 /* ambientlight_ltr329.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ACF5B3235A355BACAD2D100F5491E44A /* ambientlight_ltr329.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 0E4E66DEC5AC9906D9F1060BF38A05E1 /* version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CA94324DB1D919071BFF47D44CFE22E0 /* version.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 0F8FD28DE9A5B56025329EDD7366A8D5 /* SQLite.h in Headers */ = {isa = PBXBuildFile; fileRef = 020CDAF0FC644CAA4F4AEE55474F33DE /* SQLite.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 12DAC8BAB2F4166AFED414D575436C5E /* dfu_operations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F47F4AA73ACEAC9FDA41D36C0332414 /* dfu_operations.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 12DB32814292C66A1AE18A03D43CAD62 /* memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 20B37E395C3B2DB48FE661BCCEB47093 /* memory.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 13119889C1ED501552726A7BC718E1A6 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41E0C85C4A4ABE0F68AAF0204AA763F8 /* Coding.swift */; }; + 1344095A86FEF755B39DE3700F727A5F /* Task+Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68C951AAE97E1F47CDEDF6CCF3B94C2A /* Task+Delay.swift */; }; + 15EBC48751B6E945CF6D6F958B5C56FD /* FTS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = A47FEBBA1EE6AED3B97F30327C09C8E3 /* FTS5.swift */; }; + 1623B23C12E54E3497B668E7A4EDCFAC /* gyro_bosch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 055FA51C8FB880D13FFBCA44BD83959E /* gyro_bosch.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 1A8F21500DEEC319D3C71BCDA14D8465 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */; }; + 1B3833656A4E11A557DD596A3B4BF8F5 /* CustomFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4855729C74F392B162E88C5A7F2DCEC2 /* CustomFunctions.swift */; }; + 1DC255F222925038C5C66AB2EC838BE8 /* ComponentSliderDelegates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF3CCEC8E1F6B5E65883ED9F6FBBC95 /* ComponentSliderDelegates.swift */; }; + 1EBCA4F61F06DDF25EBF84A12E325D6D /* ColorPickerControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE7E756025845D5026763B716AB638B9 /* ColorPickerControllerProtocol.swift */; }; + 1F226F537F8460BF4EDE70AF91FC99AF /* humidity_bme280.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1315F41C173F3794DF812FFB6E4BABB1 /* humidity_bme280.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 2063F0C00C82B38FD48192CDAB1760AD /* StaticDataTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 23DD4B70DE016F8CD94A44AD063A8F60 /* StaticDataTableViewController.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 208789A7951838C97BEEEEBD5FF50952 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF8666F601E6BBF1A8CF4356C49EC82D /* CoreBluetooth.framework */; }; + 225B930E6E18E4BB031DF2266B16CCF4 /* CoreFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DD70463C6C75069EC322EC78E9B74EF /* CoreFunctions.swift */; }; + 236F810DC748332E00B01A76ECCCB4BD /* dataprocessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F0346D8A0FC45B4B2E9A5BF43D1F1424 /* dataprocessor.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 23AB401EA2DC9BAA435B033E704A9406 /* Bolts-Swift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C7160A39D7E51C78C986E9646E89AEF3 /* Bolts-Swift-dummy.m */; }; + 27B7E77F819A8046E19839CEE8C6508A /* anonymous_datasignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65CD4D32CCEF7CD1945A9206364F5D59 /* anonymous_datasignal.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 2E0E829853E688E1425CDC52E1EFCDB2 /* ColorControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AFC83344D6B8191AE1C143E1E02E283 /* ColorControl.swift */; }; + 312CA7D72386909F69240162AF215A4C /* Bridging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6830BF747190EDBF2EB01106C0C94705 /* Bridging.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 33076C7869DF4147F49A0F04A184D99C /* fts3_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = B626047F766959C564A58087ACA58F97 /* fts3_tokenizer.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 3834B3F083EAA0ACA06D0572CA4E061B /* switch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EEAC79C3B86693633106577FAA144D37 /* switch.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 3AFCEE50ED0FB18B383A344A59C1C9CE /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2203E9635BA26459CD4A8B4E1B6D422B /* Expression.swift */; }; + 3DB28F2B0FB2476C765A581F3FCDB79E /* FTS4.swift in Sources */ = {isa = PBXBuildFile; fileRef = C972E5A00474059B4961ABCDC802DD81 /* FTS4.swift */; }; + 3E16D118FE5520E9ED97FEFCB2D6FC23 /* ColorControlContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CE762A6D7D985FF99D6392847EC42E8 /* ColorControlContentView.swift */; }; + 3E7D42CBB29E683F4B21535A748ED234 /* RectangularHSBPaletteDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5741ABB2DC93CE21CD2A606D5DEEA17C /* RectangularHSBPaletteDelegate.swift */; }; + 40464E3BEC1F490F5CD23190BB86DE68 /* debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 202557B2F47A4E7B5134C438B511D6EE /* debug.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 408E6D25175C92C8DF19EC2AD52B0473 /* Task+WhenAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756D781D44346D6C9C684FFC30C24D2B /* Task+WhenAny.swift */; }; + 441F2A14F7F49F762684F592CE245FFF /* PRTweenTimingFunctions.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A738C86125947939188474A1E4339E /* PRTweenTimingFunctions.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 455CACD6876F9D77775FB1DB3E7F32B3 /* PRTween-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = AC214CCB2D7EC6565F37289452B522FE /* PRTween-dummy.m */; }; + 462FD0FA28C5564CC92A9D796397862B /* dataprocessor_config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8BD1701596BB4A36A1619F7EBEA658E /* dataprocessor_config.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 4789929283ACD4714C32A97CA3F33621 /* macro.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3589746F3729736D14CFCA7C05CDF29A /* macro.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 47E0C0DB2BBAB310D70EB1F307089699 /* ColorPickerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006410209AFD050C6245CBD2BE792B3F /* ColorPickerDelegate.swift */; }; + 48CCDC527BFC92E2B5409E8E5AA83C21 /* ColorPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBEB11AA8CDB2838B1357BC6178A45BC /* ColorPickerController.swift */; }; + 4908D6F01808E8B2C82F734B875A8B46 /* sensor_fusion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3AA4B180B473FDCCAA0F33EDC10B353E /* sensor_fusion.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 4D11A2D91AA487292C9EC05730C807A3 /* haptic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 88EF07E07BC8B02D7922894DD2D4FD83 /* haptic.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 515290B0590481E8CBE96FBBE0737386 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88AB8185F159FC1D39C785EE66D4F58A /* Helpers.swift */; }; + 521DD2B1C4D2CB2D98707B924AE1542F /* PRTween.m in Sources */ = {isa = PBXBuildFile; fileRef = 3505FB4027267F44B467A1CE3189BE2A /* PRTween.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 52663842DB5B9243AF609F68828D8490 /* accelerometer_bosch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9444C173037C985CFBA2F46F3F44477 /* accelerometer_bosch.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 567FA4BF489C0DA73E0DAED192632095 /* StaticDataTableViewController-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D4CA5689F63E231F411DB3897F60AC87 /* StaticDataTableViewController-dummy.m */; }; + 56C52024171B7188E3144EF14E8F832B /* StaticDataTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = BA09431180E518370E3EE772A93D5E51 /* StaticDataTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 57E4358DF5A349E14418DDAD0619B3E9 /* Task+ContinueWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5293B3FCC547BFBC35595164998B542 /* Task+ContinueWith.swift */; }; + 58C91B4AB36E6B16421106CA634C58EF /* MBProgressHUD-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 59EA51B0D70CEB18187D969528EF0418 /* MBProgressHUD-dummy.m */; }; + 5BAC1EF86D0E57E44E404B2796993561 /* MBProgressHUD-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 68A07C8AA447D9D1F965F51BFEA3D3B2 /* MBProgressHUD-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5CC566CCC0055546155D57902D10B574 /* Executor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93A2C54055E5EF58D751DBE7B5E910B /* Executor.swift */; }; + 5D79D26D1BE6505D813C8F7954957FE6 /* SQLite.swift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A0883C90F4487E6DD44FF9DAE921E35B /* SQLite.swift-dummy.m */; }; + 5E47EC775681C59C467F5954D516BE2D /* UIViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05CFF58B935C980A160C6C4D65A7CE00 /* UIViewExtension.swift */; }; + 5EC034ADE01051ACBE8D2F2D68105E63 /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00BDECD92C9D043B5AD82953B2BF82C2 /* utils.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 5EE41E9DF163A29E8B57721D1396221C /* datainterpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2477E023C796D61FBF59A723CC673078 /* datainterpreter.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 611443C633820C7EDA5FA856D856EB01 /* Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61AB588063CB884AA3519F769BE6EC82 /* Foundation.swift */; }; + 62B0AE5C69C426B0613E35C1105A9263 /* CGPointExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12FCF269555838BE1EB2EF3B8B421F09 /* CGPointExtension.swift */; }; + 636B54447CEE73B5F2CC4B0472D35CA4 /* TaskCompletionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ED97638BEF69DFDE5546F33EDDAFA5C /* TaskCompletionSource.swift */; }; + 66B97A52F51380108199725E357232F9 /* Setter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DEDCD99D3FF6C87DA7A9228B2EA1B73 /* Setter.swift */; }; + 67E941CADB3CDDEEDF8CE4EE4A4A05BB /* MBProgressHUD.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D0A860770A756701363AE4A26743663 /* MBProgressHUD.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 69128D7359FA88A5AD353CF5D77A8837 /* LimitedGestureViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26F31596C2054BEEE96EF39F830E211 /* LimitedGestureViewDelegate.swift */; }; + 69BDA1DCEF0ABC445229657CBB5F7674 /* Pods-MusicalCaneGame-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 478174D0C87B9553375A4A8103192D96 /* Pods-MusicalCaneGame-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6B7E366017C7AABEE05C43C4B87502F1 /* MetaWear-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 650F4F40CE2E099A10834D340BBD9EDE /* MetaWear-dummy.m */; }; + 6CA88D78EDEBF118078D06712EE8C2F3 /* ColorPickerThumbView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3476230912E363CE7F5285D6527EAE3 /* ColorPickerThumbView.swift */; }; + 71C56F0D692B6B529010D83932099612 /* neopixel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4904F9E5929463BAFB7240A014D562EF /* neopixel.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 71CA71FD244E8AB9B33C4FB32187669F /* FlexColorPicker-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 810843420244FD34B1DCCEF5EC203EEE /* FlexColorPicker-dummy.m */; }; + 74D9E0F3FAC53797E5F9894412582280 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */; }; + 7646E03FE6A36C0187301C353AA6459F /* ComponentSliderControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E82D7D0D2F0F702176329306077C600 /* ComponentSliderControls.swift */; }; + 77563A5F471F5C1F6B3B40FFCA138892 /* PRTween.h in Headers */ = {isa = PBXBuildFile; fileRef = B31634A27AC13E9EEE2F0989C18B1870 /* PRTween.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 77DD698F6FC06A9B29DCD5CC6A3F8521 /* PaletteAwareScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69C3F124C8003BE9DD9E0B347B4B24C /* PaletteAwareScrollView.swift */; }; + 7AEF07B308BAC5CF75B0DBCC591DDAAE /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC6CF370DFBFD3CB24303396CF8216F2 /* Task.swift */; }; + 7E89349F7ECE3F577C190750987E45B6 /* MetaWearScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E0DEB45E3FBA4102D9F9FB1D8E82D90 /* MetaWearScanner.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 7ECCFD1030CB4F86DD2B3DC3A2788473 /* DateAndTimeFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851BADBA8A6FFFB5EC69F243391C54B4 /* DateAndTimeFunctions.swift */; }; + 8175A97966E068EE204DA842337A1254 /* UIColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BE74803775549BE6BF46F72308B6C9 /* UIColorExtension.swift */; }; + 81E336DB50FA13C2C3BE0CF75D825058 /* Statement.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB80BE754ED06F30FA1BB8B69C24EBAA /* Statement.swift */; }; + 82F97C08FD25705A24C869FE3BB0D4F0 /* MetaWear-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 50BDC1CDDC48EE3D660BD7653DA1A8B5 /* MetaWear-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 82FBB5309A78043862B74ABE56BB6274 /* UIImageViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F087B42BF52603BAF578654BF30C2B2 /* UIImageViewExtension.swift */; }; + 842C3B7EC7E4FD50372CD78BAF3B2192 /* responseheader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF048487264D96ECB101BAD6F14FB579 /* responseheader.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 84A1479E822D0E4DE53C9C22CF0143D8 /* MblMwGattChar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 084321B9DB2861041514FA3802DBF807 /* MblMwGattChar.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 86892C0DFD831D8516EC74849253FDD9 /* CBUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07EB6AC6BAB46765B87C1854FC9D24FA /* CBUUID.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 8740838639CB0A07D62838C670E294F6 /* ColorPreviewWithHex.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69724E22F6FC9383261352112F37AE7 /* ColorPreviewWithHex.swift */; }; + 8B018EB5C72A9BBCE7518F98744DA0DE /* Collation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9166DFD798F4A1606D7677551E3BD4EC /* Collation.swift */; }; + 8C57BD382B1E923211E9FC1346211BE1 /* colordetector_tcs34725.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 72F91017E90ACD4FCE83A3485695C412 /* colordetector_tcs34725.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 8DA3C6CF294542E420FBC089D70234F4 /* HSBColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D15B0AD76D08E576C8490AAE7DCB6FE4 /* HSBColor.swift */; }; + 8E275DB6B02EC508FCCA47512A2A5BB5 /* Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F0F495A31ECF7DBEEB5653F543F0FF2 /* Schema.swift */; }; + 8EAC37DD9A8F09AFAE51AAC1DB22B5B7 /* PRTweenTimingFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = A8F2C63252A09E44D38172A5608073A1 /* PRTweenTimingFunctions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9304E779EF93A87099DF87507B5E525A /* PaletteControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5C7C98E5F43A5EDD0E9807FD85025C0 /* PaletteControls.swift */; }; + 93AF51ECF865332C7E9BAF670E370FC1 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BD1D885F3A9889ED88A68F6C0F90CB /* Query.swift */; }; + 95355AF97A4A9D84DE7000A789301CA8 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBA57D212A040C675CF8A6B7BDECCC7C /* GradientView.swift */; }; + 95E46181D8FC4AC4C20F177220805D59 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47834DBA79AF16C25F6D7EA5E5155B13 /* Errors.swift */; }; + 96ED90E71125694BFDCC554BB5F68CC0 /* StaticDataTableViewController-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 406C98AC09D595E5C506DE76BF364909 /* StaticDataTableViewController-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 97418B166FBD270A593014C58AAED10A /* LimitedGestureCircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED32DC6A70AA2AEEB654F90782756768 /* LimitedGestureCircleView.swift */; }; + 9C0AC3E090248A91117CB3F0C8D24648 /* moduleinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0835B59033E67470EFD8A9B7D3F477A1 /* moduleinfo.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + 9CE445FA94FCD69779725FA2440A6FD8 /* AdjustedHitBoxColorControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4696B4A78EB5B5B2019A21FEF3C142FB /* AdjustedHitBoxColorControl.swift */; }; + 9D1330DC67167B9BE31E129E9DAA5717 /* ColorPaletteDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF47640DFEBCE252FBAA774FBE6F42F1 /* ColorPaletteDelegate.swift */; }; + 9D3F78280E13C21A6E67051750748ECB /* accelerometer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B7C0CCB48AA3B057268428EC76303DFC /* accelerometer.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + A37E983640B559194177C2A7E2F72FC9 /* MetaWearData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E51668FB3B651E6FE54DCD75388792D /* MetaWearData.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + A4363ECC3F8EA39A4FE0D8A84DABC6E0 /* CircleShapedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CECA536350ADA0B8271E80F831A15FBA /* CircleShapedView.swift */; }; + A4CBDE2B1DFCCBB9795F8142C739B836 /* ControlWithThumbView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C846A5D44EB3A55B8C787DC3D91CCF /* ControlWithThumbView.swift */; }; + A5F3F9F28C467C2B3294D164D0E574C2 /* event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28A378F9A01525E97149ABB8DCA5B1CC /* event.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + A90332024C9411863217799521D89900 /* ColorSliderControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68270A8D2FCE48DD4B73F8783B5E0F17 /* ColorSliderControl.swift */; }; + A9ECF13DC52C6742BFFCA3112B62B975 /* Task+WhenAll.swift in Sources */ = {isa = PBXBuildFile; fileRef = D931D5E916522AE487B7B84F28F872B2 /* Task+WhenAll.swift */; }; + AA068FACD628B4D9F72DA0B5294F8F8F /* FlexColorPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E5CB155C33429C2CEA4B8DBAE6B5C05 /* FlexColorPicker.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AB240671C15F1E8759FE431FCDB34FF2 /* ColorPaletteControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 748E831377F55E2DEFF12C9EAD1EDA36 /* ColorPaletteControl.swift */; }; + ABCDA56D252176659A1A1D9BFDD726D7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */; }; + AC178C8BC13F6BB812CF480DB5DF74CE /* FlexColorPicker-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A2F747328473C2A352F6941CF34BD8 /* FlexColorPicker-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AE509515FB5C6503228AA70CC68FE759 /* PRTween-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 80A006ECE0C1D98020B9C6469CBAEF3A /* PRTween-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AE57D9B6AB12C36064C26DA4E1AE3FAE /* MetaWear.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99BD5F29CB67E3572EB2165C71C69402 /* MetaWear.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + AFAC1D4EBD53A048346210536741DF13 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FEEEB3439CFFFDE16B34BD12D5B91522 /* CoreGraphics.framework */; }; + B03D2A549C8060B988688B7E6ED9B2F0 /* magnetometer_bmm150.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BB8A576C5797EB68CB23964A394D94C /* magnetometer_bmm150.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + B1F915ADA0E5011C8B6FD1590BB17779 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21FD84CE28F5CB27543CFC6542AC55F8 /* Operators.swift */; }; + B2E884D979703A70ABAEB807118667B0 /* Value.swift in Sources */ = {isa = PBXBuildFile; fileRef = A735833176106989D12FB071A9461289 /* Value.swift */; }; + B52177FF72FDAC3EDB7195DE98F5501E /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC852EC78B5163CEFEF2E069E7BA4BE1 /* QuartzCore.framework */; }; + B5CED12449A48B4C5CF3EC41C40C8657 /* miniz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 89590357DAA3D6FE1273B2AA18B10370 /* miniz.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + B86419765F5D00C53B7DAEC72EA8DD8D /* UIViewWithCommonInit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9D2F75D9E329E80A4A9A2F989DDAC9 /* UIViewWithCommonInit.swift */; }; + B8FF77D7757DB0127BC2A73B7422494B /* accelerometer_mma8452q.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B48995017BA31F28C04293A293DB8B0 /* accelerometer_mma8452q.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + BA34CF2F245554A7F86056CAD1A081B3 /* dfu_operations_details.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 204375FBD2222484868C2AE46A076980 /* dfu_operations_details.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + BBDF31B34E37575116AEDEBF2BB9B701 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */; }; + BCB035BFC809F5A092499DFE9319E967 /* AbstractColorControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = E065478487EB7C68D6F625F7BF7A1DA6 /* AbstractColorControl.swift */; }; + C0E08E3F92F4FD10789F379EFCB2D0C4 /* RadialHSBPaletteDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B381E4993D646F1889B08E2056F6B10 /* RadialHSBPaletteDelegate.swift */; }; + C12B2FDD84963FC6CF69851F45E9C7C8 /* multichanneltemperature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8F89C30C49386D56C5D3FF459FA8B560 /* multichanneltemperature.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + C2896E99CF6C700E0CFC00B11CFFC0E4 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3630A278B75627E12EA0ECF03C448D /* UIImageExtension.swift */; }; + C4048C494F0BDB084E14B2BFD4BA6748 /* String+VersionCompare.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A531C4413D4A9678D8FA425EA53734 /* String+VersionCompare.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + C6316CBFF2CE41DB8CC35E2D9F92A183 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = 619D18BEE833C4348EAF940808AA2B11 /* SQLite-Bridging.m */; }; + C6D8FD5291EC0ABDBBB2622C1BB5071D /* DeviceInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E936650895E5617726CF0BD2093EE0 /* DeviceInformation.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + CBB815550C11587460B621667135F8C0 /* gpio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8E2005539348BC2EC04A37B194E1D027 /* gpio.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + CC3C199126AE869B04775F7EB624CE33 /* cbindings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B7CB030AD099F3C8A3F365D79A48586 /* cbindings.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + CDC4102412F60312687D09D89421D65A /* settings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B682398687C85519B90ED18DBEE7951 /* settings.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + CDE77621403690BFBE5FE3AF54957207 /* LogDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E837DDBD7E6B0A0B51BCC223AB74E2F /* LogDelegate.swift */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + CE5067B38ACA71E582DF300E3DCD7372 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */; }; + CE8321A708B897CB83CE0B7070B5DEC5 /* barometer_bosch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CA18725CA461815A2D0005D908942870 /* barometer_bosch.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + CF58C73A6AD2F5E21141E0F584E7C03F /* conductance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E22536D52AAC69C2C171FDAB5083E20B /* conductance.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + D0DD5463F075AA2300AA953722562725 /* Bolts-Swift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 856008788ABB599F1BEA9ECE9C974858 /* Bolts-Swift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D1F5650A0095D2691F9DABB6B430A273 /* ibeacon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 590BAB70520695F7005DBB2221F72974 /* ibeacon.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + D2E8A1533C2842208EDE5465065EC9B1 /* metawearboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AB3434E3EC03D58E5256B36E21F667E /* metawearboard.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + D6BA34B49D11A0928AAF296271D59E35 /* serialpassthrough.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1761180BE85C04EE61182D0C9ECE6D82 /* serialpassthrough.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + D80AA1B238162FA2B61ACE9F4F4BBC3C /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEAB9015993CEBB553A0414679F7395D /* RTree.swift */; }; + D9F21A635BAA8BB36A68B88DFE16C6EE /* Blob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81B6F2535F4EE9FA4A2315176F72688B /* Blob.swift */; }; + DC712E51ADB04BC6D8E77C5071D80511 /* proximity_tsl2671.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B99CC70D3AFA59FB6FE09F278637FBC /* proximity_tsl2671.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + DCA7D1243C9CCD5A9FA134159633BCBD /* logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CD32BC358ADAD2D2224880C6512FE29 /* logging.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + DF319F241395FA2C87858B88D62652AB /* led.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2DB10B9B88AEAF7203CF4E5E6BCED7DC /* led.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + DFBD8D4EE2FFE0DD2D33EFC09EF3308C /* dfu_utility.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CC2C0DCF05FC714271C90C86A6877FC /* dfu_utility.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + E63D535FB00AE703521EBEC08AF90092 /* task.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41F889C88E2EAA1759E630D7B46E37AF /* task.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + E75B43A0CE1D24F53CD568AF709EB23B /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17A9577AA604425FBE9BE62410A72561 /* Errors.swift */; }; + E9D69372A158F024635C786160B2D719 /* Pods-MusicalCaneGame-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 448E2B4D025708620E619D128E766E36 /* Pods-MusicalCaneGame-dummy.m */; }; + ED487585601DAA373D1F4B233BA36C20 /* file_operations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4E361A5F54DAAE628EE9C57E66FB6063 /* file_operations.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + EF15B6B49DE8995CF11B76BA55FBB854 /* async_creator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A31050EA589DAF8798D4F5FD0C699B2A /* async_creator.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + F47ADF6F6C2B9137A8972E40AD2D2C29 /* CustomColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 767F239AADD5DE5511FC5DB522D50055 /* CustomColorPickerViewController.swift */; }; + F787290691C3327279C5247437331634 /* threadpool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C7E47F325908076A46464074F516599 /* threadpool.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + FA4165C30F007120A0061D64985A1C3E /* CGRectExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4B70F59939EEA547A42705D781E63C /* CGRectExtension.swift */; }; + FA90AA80C6FD95C594DFD4955C3EA556 /* ColorSliderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE3C58FBE30DA1BAAA46853AB653154E /* ColorSliderDelegate.swift */; }; + FB8E1CA1F50552E2A184B5EED802381F /* datasignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E9B1FC1E22EF18BD3AC50CE41FFB8FCF /* datasignal.cpp */; settings = {COMPILER_FLAGS = "-Wno-documentation -Wno-comma"; }; }; + FCDB25BAC24D043C17317C7289249096 /* AggregateFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437E87C04ED10A10DE2D29A5C9F52D66 /* AggregateFunctions.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 13CAF08B6968493593A894786C3FDEFB /* PBXContainerItemProxy */ = { + 010E464B7807A1ACB3A1262CBD7D1E9C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 42465A188431886AB035275F049824D3; - remoteInfo = Bolts; + remoteGlobalIDString = 75CA230D0637BEBCCBE6371A0E6B5B6B; + remoteInfo = PRTween; }; - 26D9B30409B4FC48E8C4E29203EB465F /* PBXContainerItemProxy */ = { + 253BB08B82188324D8CC61B5DEDB276C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = 9A9A6DFBF33C0809BD9B32C8C8B776E8; remoteInfo = FlexColorPicker; }; - 58E83F60DCD5800A6C4C8868EAEB530C /* PBXContainerItemProxy */ = { + 25D1465F5BAD756AE9887F8324BA296F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 82B0A41D3031FF27D78E17B0A9A46FB0; - remoteInfo = MBProgressHUD; + remoteGlobalIDString = BA1CEDB360B77644C934EAD86B37FCB5; + remoteInfo = "Bolts-Swift"; }; - 68F9646952DB355BB4ADB27C394FFF1F /* PBXContainerItemProxy */ = { + 57CCF59C2EF075AD8E32672C90F88DBE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 8CB1610D02CF2E1138DAFFDA5722B39A; - remoteInfo = FastCoding; + remoteGlobalIDString = 82B0A41D3031FF27D78E17B0A9A46FB0; + remoteInfo = MBProgressHUD; }; - B72B2DB8AEEB766DA7B3825A4399A2D5 /* PBXContainerItemProxy */ = { + 6983B19336F847EE094A8132C7989574 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = 7121634C8DA4533EB626AEE3C697BFAB; remoteInfo = StaticDataTableViewController; }; - D4C06B02139C9EFA738B055C77916119 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 42465A188431886AB035275F049824D3; - remoteInfo = Bolts; - }; - D6A936BABE57C21FA91A3D5B85C922B9 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 3F2C1776D90B62B156DB52C41A5C419C; - remoteInfo = SQLite.swift; - }; - E5CE14FF76BF971E6DEEE6A650ED1860 /* PBXContainerItemProxy */ = { + 7B66B4F4C278ACDE73A87A9588CFF100 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 5F93A6259A037F8247AD055CC3E8F98E; - remoteInfo = MetaWearPrivate; + remoteGlobalIDString = BA1CEDB360B77644C934EAD86B37FCB5; + remoteInfo = "Bolts-Swift"; }; - F0361704E4EB686B9FEDDB25A4B1F9FC /* PBXContainerItemProxy */ = { + 9DDB087D92E14D38907D84D956273CEB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 75CA230D0637BEBCCBE6371A0E6B5B6B; - remoteInfo = PRTween; + remoteGlobalIDString = 3E8BB3BAFA6478784A9A7DD76C8A1F3C; + remoteInfo = MetaWear; }; - FE114F40E0FFAEBA98C12D996359EA72 /* PBXContainerItemProxy */ = { + FC3AAE0A8D05ADC48DB649184C581E08 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 8CB1610D02CF2E1138DAFFDA5722B39A; - remoteInfo = FastCoding; + remoteGlobalIDString = 3F2C1776D90B62B156DB52C41A5C419C; + remoteInfo = SQLite.swift; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 0035D91A4EFD0627194FE64A3B48F79F /* MBLCommand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLCommand.h; path = MetaWear/Internal/Modules/Command/MBLCommand.h; sourceTree = ""; }; - 0131DF0EF949A15A0646568D00541439 /* MBLPhotometer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLPhotometer.m; path = MetaWear/Classes/Modules/Photometer/MBLPhotometer.m; sourceTree = ""; }; - 0181593C309048FF98276EB66B259494 /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = Sources/SQLite/Core/Errors.swift; sourceTree = ""; }; - 02D36FC3DB28544278D49A5526ED7097 /* MBLMetaWearManager+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLMetaWearManager+Private.h"; path = "MetaWear/Internal/Core/MBLMetaWearManager+Private.h"; sourceTree = ""; }; - 03AAABEF834082B42949BFF22663E639 /* MBLPhotometer+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLPhotometer+Private.h"; path = "MetaWear/Internal/Modules/Photometer/MBLPhotometer+Private.h"; sourceTree = ""; }; - 0507AD00A7595EC938575D499440F9BE /* StaticDataTableViewController-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "StaticDataTableViewController-Info.plist"; sourceTree = ""; }; - 05FA13B1682546E889E7F5EF918EDEF5 /* MBLiBeacon.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLiBeacon.m; path = MetaWear/Classes/Modules/iBeacon/MBLiBeacon.m; sourceTree = ""; }; - 060C6688EBD31FE399EEF457BEB46DF4 /* ColorControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorControl.swift; path = FlexColorPicker/Classes/Controls/ColorControl.swift; sourceTree = ""; }; - 080EAFE4FDF6348B7223C1C772604E15 /* PRTween-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PRTween-prefix.pch"; sourceTree = ""; }; - 081C57DE88C04918BB9D408885753169 /* MBLGyroBMI160PackedDataReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGyroBMI160PackedDataReadyEvent.m; path = MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160PackedDataReadyEvent.m; sourceTree = ""; }; - 0841698E1D51A9F98486360941631FC4 /* MBLAccelerometerBoschLowOrHighGEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschLowOrHighGEvent.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschLowOrHighGEvent.m; sourceTree = ""; }; - 0898A84F8AFB64E5EA38D125E0BA00AF /* ColorPickerControllerProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPickerControllerProtocol.swift; path = FlexColorPicker/Classes/ColorPickerControllerProtocol.swift; sourceTree = ""; }; - 0908E566C0DB4EF23AE31DF93476D076 /* MBLExternalThermistor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLExternalThermistor.h; path = MetaWear/Classes/Modules/Temperature/MBLExternalThermistor.h; sourceTree = ""; }; - 09D173DEE35AC8F637F76E98BAA98367 /* MBLAccelerometerShakeEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerShakeEvent.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerShakeEvent.h; sourceTree = ""; }; - 0A32C7003976797CB7E261BC2F4EFA18 /* MBLEntityModule.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLEntityModule.m; path = MetaWear/Classes/Core/MBLEntityModule.m; sourceTree = ""; }; - 0A80AAF5A16E49D99665CDBB7DB5F417 /* MBLData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLData+Private.h"; path = "MetaWear/Internal/Core/MBLData+Private.h"; sourceTree = ""; }; - 0CC9FC024573932A6B57179D1A27FBC1 /* MBLTemperatureV0.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLTemperatureV0.h; path = MetaWear/Internal/Modules/Temperature/MBLTemperatureV0.h; sourceTree = ""; }; - 0D25B6E79539085C97CB8B9387F181B8 /* MBLDownloadOnlyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLDownloadOnlyEvent.h; path = MetaWear/Internal/Core/MBLDownloadOnlyEvent.h; sourceTree = ""; }; - 0E4CB215E9687C8D91C0023BBD18DEF0 /* Query.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Query.swift; path = Sources/SQLite/Typed/Query.swift; sourceTree = ""; }; - 0F164C3F15CFB0FD52FD5C684DCE5CE9 /* MBLSensorFusion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLSensorFusion.h; path = MetaWear/Classes/Modules/SensorFusion/MBLSensorFusion.h; sourceTree = ""; }; - 0F61A31F5F27DBB0BD934BC6571F76C1 /* MBLAccelerometerMMA8452QFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerMMA8452QFormat.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452QFormat.h; sourceTree = ""; }; - 0F71375DD28767C26672DFD841B1BE72 /* MBLAccelerometerBMA255.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBMA255.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMA255/MBLAccelerometerBMA255.h; sourceTree = ""; }; - 0FD03161B220A16CBBC96747CD6F2A10 /* ColorPickerDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPickerDelegate.swift; path = FlexColorPicker/Classes/ColorPickerDelegate.swift; sourceTree = ""; }; - 10F5BAC0567A9C558CC3AB8CF1EE3D1A /* MBLAccelerometerBMA255MotionEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBMA255MotionEvent+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMA255/MBLAccelerometerBMA255MotionEvent+Private.h"; sourceTree = ""; }; - 1279087722BFA08A2563C4186EA02B32 /* MBLAccelerometerBoschRMSFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschRMSFormat.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschRMSFormat.h; sourceTree = ""; }; - 12800A27E25D3F547A046667FE9DAA03 /* MBLEntityEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLEntityEvent.m; path = MetaWear/Classes/Core/MBLEntityEvent.m; sourceTree = ""; }; - 1292C8E610760DB6D2DAF8A9F2109BDE /* MBLAccelerometerBMI160MotionEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBMI160MotionEvent.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMI160/MBLAccelerometerBMI160MotionEvent.h; sourceTree = ""; }; - 1455523005F45E1DEB1BF69539D10967 /* MBLBarometerBosch+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLBarometerBosch+Private.h"; path = "MetaWear/Internal/Modules/Barometer/BarometerBosch/MBLBarometerBosch+Private.h"; sourceTree = ""; }; - 145C4BA58ECB001DD5537B43D7365413 /* MBLMagnetometerBMM150.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMagnetometerBMM150.h; path = MetaWear/Classes/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150.h; sourceTree = ""; }; - 15B1F99EC4F214371CF2234D359734D6 /* MBLPhotometerTCS3472Format.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLPhotometerTCS3472Format.m; path = MetaWear/Internal/Modules/Photometer/PhotometerTCS3472/MBLPhotometerTCS3472Format.m; sourceTree = ""; }; - 15DEFC6322F383667D9163F4CA090C54 /* MBLNumericFormatter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLNumericFormatter.m; path = MetaWear/Internal/Core/MBLNumericFormatter.m; sourceTree = ""; }; - 15EAE4E3DFB78431354404D1917E8D9A /* MetaWearPrivate.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = MetaWearPrivate.modulemap; sourceTree = ""; }; - 15F2D265A6C06CC541A908919C149B97 /* MBLAccelerometerBoschDataReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschDataReadyEvent.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschDataReadyEvent.h; sourceTree = ""; }; - 163E1C0C54636289C825D0724BD976AF /* BFTask+Exceptions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "BFTask+Exceptions.m"; path = "Bolts/Common/BFTask+Exceptions.m"; sourceTree = ""; }; - 177961493C41A3EA823992816120FAEE /* PRTweenTimingFunctions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PRTweenTimingFunctions.h; path = lib/PRTweenTimingFunctions.h; sourceTree = ""; }; - 177E694248790CEB1B03BC3481CFED6D /* MBLLoggingV1.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLLoggingV1.h; path = MetaWear/Internal/Modules/Logging/MBLLoggingV1.h; sourceTree = ""; }; - 17F41492695945037081DBB883B13048 /* MBLTimerEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLTimerEvent.m; path = MetaWear/Classes/Modules/Timer/MBLTimerEvent.m; sourceTree = ""; }; - 1873C5BE50DCCCBECF6498A78492DFFC /* FlexColorPicker-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FlexColorPicker-dummy.m"; sourceTree = ""; }; - 18BCDEA1BB8E632240F8D90D2EC39ABC /* fts3_tokenizer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = Sources/SQLiteObjc/fts3_tokenizer.h; sourceTree = ""; }; - 192865505A11585EE708054437C64D0B /* SQLite.swift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SQLite.swift.debug.xcconfig; sourceTree = ""; }; - 19C89EECF5C0B13F35AEEF99D8418005 /* MBLAccelerometerBoschRMSFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschRMSFormat.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschRMSFormat.m; sourceTree = ""; }; - 1A0AEDBAEC7541B87CE8246EF7E685BF /* MBLBluetoothCentralMock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBluetoothCentralMock.m; path = MetaWear/Internal/Mocks/MBLBluetoothCentralMock.m; sourceTree = ""; }; - 1A1ADBF675F2197D8BDC63EFAB0173CB /* CGRectExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CGRectExtension.swift; path = FlexColorPicker/Classes/Utilities/CGRectExtension.swift; sourceTree = ""; }; - 1A4226CABDC9A7A1AB311F018CC7FCFB /* MBLBarometerBMP280.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBarometerBMP280.m; path = MetaWear/Classes/Modules/Barometer/BarometerBosch/BarometerBMP280/MBLBarometerBMP280.m; sourceTree = ""; }; - 1A7459BA29DBA3A3E33E19765B2D9FE3 /* StaticDataTableViewController.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = StaticDataTableViewController.release.xcconfig; sourceTree = ""; }; - 1A837EA4F931F8F22DB23E84BA700143 /* MBLAccelerometerBMI160.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBMI160.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMI160/MBLAccelerometerBMI160.m; sourceTree = ""; }; - 1B2496EFD101ED42CCB429E14049A6A6 /* MBLLoggingV1.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLLoggingV1.m; path = MetaWear/Internal/Modules/Logging/MBLLoggingV1.m; sourceTree = ""; }; - 1BD01F654DE5D06ED7C89636CDE53A98 /* MBLAccelerometerTapEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerTapEvent.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerTapEvent.h; sourceTree = ""; }; - 1C7BB0D32F5255CE1D02B13A3FA4B89C /* MBLMagnetometer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMagnetometer.m; path = MetaWear/Classes/Modules/Magnetometer/MBLMagnetometer.m; sourceTree = ""; }; - 1C8F2D1B54544E1C5892E95341D19CB9 /* MBLAmbientLightLTR329.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAmbientLightLTR329.m; path = MetaWear/Classes/Modules/AmbientLight/AmbientLightLTR329/MBLAmbientLightLTR329.m; sourceTree = ""; }; - 1DB3F0AF535DD95F163B334A50BC36DF /* MBLHygrometerBME280PeriodicHumidityEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLHygrometerBME280PeriodicHumidityEvent.h; path = MetaWear/Internal/Modules/Hygrometer/HygrometerBME280/MBLHygrometerBME280PeriodicHumidityEvent.h; sourceTree = ""; }; - 1F8E304B92A2F672CC202EDC0422B1E9 /* MBLDeviceInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLDeviceInfo.h; path = MetaWear/Classes/Core/MBLDeviceInfo.h; sourceTree = ""; }; - 1FD9FA47B74B1AC08CBDFD649C1EDBAF /* MBLAccelerometerMMA8452Q+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerMMA8452Q+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452Q+Private.h"; sourceTree = ""; }; - 2041271A141C45AC517D17888B5AB562 /* MBLGPIOPin+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLGPIOPin+Private.h"; path = "MetaWear/Internal/Modules/GPIO/MBLGPIOPin+Private.h"; sourceTree = ""; }; - 221760E26EFB265491A7EB9E276FA14F /* MBLTimer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLTimer.h; path = MetaWear/Classes/Modules/Timer/MBLTimer.h; sourceTree = ""; }; + 006410209AFD050C6245CBD2BE792B3F /* ColorPickerDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPickerDelegate.swift; path = FlexColorPicker/Classes/ColorPickerDelegate.swift; sourceTree = ""; }; + 00BDECD92C9D043B5AD82953B2BF82C2 /* utils.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = utils.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/utils.cpp"; sourceTree = ""; }; + 020CDAF0FC644CAA4F4AEE55474F33DE /* SQLite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SQLite.h; path = Sources/SQLite/SQLite.h; sourceTree = ""; }; + 036D251389EC6686A9FDFF11C295F0B4 /* FlexColorPicker.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FlexColorPicker.modulemap; sourceTree = ""; }; + 055FA51C8FB880D13FFBCA44BD83959E /* gyro_bosch.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = gyro_bosch.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gyro_bosch.cpp"; sourceTree = ""; }; + 05CFF58B935C980A160C6C4D65A7CE00 /* UIViewExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIViewExtension.swift; path = FlexColorPicker/Classes/Utilities/UIViewExtension.swift; sourceTree = ""; }; + 07EB6AC6BAB46765B87C1854FC9D24FA /* CBUUID.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CBUUID.swift; path = MetaWear/Core/CBUUID.swift; sourceTree = ""; }; + 0835B59033E67470EFD8A9B7D3F477A1 /* moduleinfo.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = moduleinfo.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/moduleinfo.cpp"; sourceTree = ""; }; + 084321B9DB2861041514FA3802DBF807 /* MblMwGattChar.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MblMwGattChar.swift; path = MetaWear/Core/MblMwGattChar.swift; sourceTree = ""; }; + 0BF3CCEC8E1F6B5E65883ED9F6FBBC95 /* ComponentSliderDelegates.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ComponentSliderDelegates.swift; path = FlexColorPicker/Classes/ControlDelegates/ComponentSliderDelegates.swift; sourceTree = ""; }; + 0CDA1FE502B946D587F0D299109AD287 /* MBProgressHUD-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "MBProgressHUD-Info.plist"; sourceTree = ""; }; + 0D0A860770A756701363AE4A26743663 /* MBProgressHUD.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = MBProgressHUD.h; sourceTree = ""; }; + 0F087B42BF52603BAF578654BF30C2B2 /* UIImageViewExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIImageViewExtension.swift; path = FlexColorPicker/Classes/Utilities/UIImageViewExtension.swift; sourceTree = ""; }; + 1117B4651FA1A8584AA3B198D1592A04 /* timer.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = timer.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/timer.cpp"; sourceTree = ""; }; + 12B347F97086190A06909E4EC2E6D349 /* SQLite.swift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SQLite.swift.release.xcconfig; sourceTree = ""; }; + 12FCF269555838BE1EB2EF3B8B421F09 /* CGPointExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CGPointExtension.swift; path = FlexColorPicker/Classes/Utilities/CGPointExtension.swift; sourceTree = ""; }; + 1315F41C173F3794DF812FFB6E4BABB1 /* humidity_bme280.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = humidity_bme280.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/humidity_bme280.cpp"; sourceTree = ""; }; + 1579A0986D70C32D7BED1A855C31EF4B /* BoltsSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BoltsSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 16C81353C57A838AFF0848801B54CC23 /* SQLite-Bridging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "SQLite-Bridging.h"; path = "Sources/SQLiteObjc/include/SQLite-Bridging.h"; sourceTree = ""; }; + 1761180BE85C04EE61182D0C9ECE6D82 /* serialpassthrough.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = serialpassthrough.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/serialpassthrough.cpp"; sourceTree = ""; }; + 17A9577AA604425FBE9BE62410A72561 /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = Sources/SQLite/Core/Errors.swift; sourceTree = ""; }; + 18A531C4413D4A9678D8FA425EA53734 /* String+VersionCompare.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "String+VersionCompare.swift"; path = "MetaWear/Core/String+VersionCompare.swift"; sourceTree = ""; }; + 18A738C86125947939188474A1E4339E /* PRTweenTimingFunctions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PRTweenTimingFunctions.m; path = lib/PRTweenTimingFunctions.m; sourceTree = ""; }; + 18D894726DE00A174BEAABE67F40DF6C /* Bolts-Swift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Bolts-Swift.release.xcconfig"; sourceTree = ""; }; + 1E82D7D0D2F0F702176329306077C600 /* ComponentSliderControls.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ComponentSliderControls.swift; path = FlexColorPicker/Classes/Controls/ComponentSliderControls.swift; sourceTree = ""; }; + 1E9D2F75D9E329E80A4A9A2F989DDAC9 /* UIViewWithCommonInit.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIViewWithCommonInit.swift; path = FlexColorPicker/Classes/Views/UIViewWithCommonInit.swift; sourceTree = ""; }; + 202557B2F47A4E7B5134C438B511D6EE /* debug.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = debug.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/debug.cpp"; sourceTree = ""; }; + 204375FBD2222484868C2AE46A076980 /* dfu_operations_details.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = dfu_operations_details.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations_details.cpp"; sourceTree = ""; }; + 20B37E395C3B2DB48FE661BCCEB47093 /* memory.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = memory.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/memory.cpp"; sourceTree = ""; }; + 21FD84CE28F5CB27543CFC6542AC55F8 /* Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/SQLite/Typed/Operators.swift; sourceTree = ""; }; + 2203E9635BA26459CD4A8B4E1B6D422B /* Expression.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Expression.swift; path = Sources/SQLite/Typed/Expression.swift; sourceTree = ""; }; 23244125E4D078FC166E1A8E8DD4C362 /* Pods-MusicalCaneGame.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-MusicalCaneGame.modulemap"; sourceTree = ""; }; - 23907A2905EA3FA33DADE5E90FC69BED /* MBLConductanceData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLConductanceData.h; path = MetaWear/Internal/Modules/Conductance/MBLConductanceData.h; sourceTree = ""; }; - 23A28F0383C296A9AB950400B3387147 /* MBLGyro+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLGyro+Private.h"; path = "MetaWear/Internal/Modules/Gyro/MBLGyro+Private.h"; sourceTree = ""; }; - 2419ECD02B38092140406C63872E7680 /* CGPointExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CGPointExtension.swift; path = FlexColorPicker/Classes/Utilities/CGPointExtension.swift; sourceTree = ""; }; - 2467DB704F5E928FE637376D0A496718 /* MBLAccelerometerTapEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerTapEvent.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerTapEvent.m; sourceTree = ""; }; - 246B555E509917B4C8FE7D6D29CDD369 /* ColorPaletteControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPaletteControl.swift; path = FlexColorPicker/Classes/Controls/ColorPaletteControl.swift; sourceTree = ""; }; - 24D99B6BC6E29F9502C48BAB16605393 /* MBLAccelerometerBoschTapEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBoschTapEvent+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschTapEvent+Private.h"; sourceTree = ""; }; - 252387757419D8BD4A16B5BB34E49F89 /* FastCoding.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FastCoding.release.xcconfig; sourceTree = ""; }; - 252750A7AFDD794CFFE923FCE3F738ED /* BFCancellationToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationToken.h; path = Bolts/Common/BFCancellationToken.h; sourceTree = ""; }; - 25FA6D0F03DE44901187E3563AD33707 /* MBLAccelerometerBMA255.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBMA255.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMA255/MBLAccelerometerBMA255.m; sourceTree = ""; }; - 2608EBF86FD05C8C65787DD976E8A7A3 /* MBLExternalThermistor0.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLExternalThermistor0.h; path = MetaWear/Internal/Modules/Temperature/MBLExternalThermistor0.h; sourceTree = ""; }; - 2645876D1AD9695760FD68927753D24E /* MBLAccelerometer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometer.h; path = MetaWear/Classes/Modules/Accelerometer/MBLAccelerometer.h; sourceTree = ""; }; - 27375EFF0029352930FC350FA1958789 /* MBLAccelerometerDataReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerDataReadyEvent.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerDataReadyEvent.h; sourceTree = ""; }; - 2754222A4444878B4FE2DFA4619E1593 /* MBLQuaternionFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLQuaternionFormat.m; path = MetaWear/Internal/Modules/SensorFusion/MBLQuaternionFormat.m; sourceTree = ""; }; - 28443468DB16E07440FDC8A271BCB2A2 /* FastCoding-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FastCoding-prefix.pch"; sourceTree = ""; }; - 28D619B87C03D8885E04BDB6D3672B5B /* MBLNumericFormatter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLNumericFormatter.h; path = MetaWear/Internal/Core/MBLNumericFormatter.h; sourceTree = ""; }; - 2A6F4150D266A40B8F330513CCE21781 /* MBLSensorFusion+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLSensorFusion+Private.h"; path = "MetaWear/Internal/Modules/SensorFusion/MBLSensorFusion+Private.h"; sourceTree = ""; }; - 2A6FFF11EC07CE95E9550644682930EE /* MBLAccelerometerBMA255+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBMA255+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMA255/MBLAccelerometerBMA255+Private.h"; sourceTree = ""; }; - 2A92E56CD0DA9567C0D2C38269029A45 /* MBLDataSample.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLDataSample.m; path = MetaWear/Classes/Core/MBLDataSample.m; sourceTree = ""; }; - 2B364C63A62EB39DC5DD8139922E3E5A /* MBLAccelerometerData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerData+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/MBLAccelerometerData+Private.h"; sourceTree = ""; }; - 2B7F010F3BCC8E3ED586A840E274BACE /* MetaWearPrivate.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MetaWearPrivate.debug.xcconfig; sourceTree = ""; }; - 2BE3ABA4E60E29199045F2A64CD74F91 /* MBLAccelerometerBMI160StepEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBMI160StepEvent.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMI160/MBLAccelerometerBMI160StepEvent.m; sourceTree = ""; }; - 2C46D371D69D1FF5F5FA74A437E899D3 /* MBLI2CData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLI2CData.m; path = MetaWear/Classes/Modules/Serial/MBLI2CData.m; sourceTree = ""; }; - 2CF9E215545AF0D84ECF3C631CC3958C /* MBLGyroBMI160.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGyroBMI160.h; path = MetaWear/Classes/Modules/Gyro/GyroBMI160/MBLGyroBMI160.h; sourceTree = ""; }; - 2D199B40598C2ED9D0CBE7BBB0823967 /* MBLHygrometer+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLHygrometer+Private.h"; path = "MetaWear/Internal/Modules/Hygrometer/MBLHygrometer+Private.h"; sourceTree = ""; }; - 2DA2162B1DE380D357939F9498BD8311 /* Bolts.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Bolts.release.xcconfig; sourceTree = ""; }; - 2DD12BA668FAAE372DD539EC9C82734C /* BFCancellationTokenSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationTokenSource.h; path = Bolts/Common/BFCancellationTokenSource.h; sourceTree = ""; }; - 2E827CD701EF38921B89B7BC7DF0EE9D /* MBProgressHUD.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = MBProgressHUD.modulemap; sourceTree = ""; }; - 2F05B37F717732E30D752E7C5D3F1201 /* DefaultColorPickerViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultColorPickerViewController.swift; path = FlexColorPicker/Classes/DefaultColorPickerViewController.swift; sourceTree = ""; }; - 2F671A45BF53AE08C5B8E3BE22A901D1 /* Bolts-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Bolts-umbrella.h"; sourceTree = ""; }; - 30278A2896EBED27D7B8B4A499988944 /* MBLAnalytics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAnalytics.h; path = MetaWear/Internal/Core/MBLAnalytics.h; sourceTree = ""; }; + 23DD4B70DE016F8CD94A44AD063A8F60 /* StaticDataTableViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = StaticDataTableViewController.m; sourceTree = ""; }; + 2477E023C796D61FBF59A723CC673078 /* datainterpreter.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = datainterpreter.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/datainterpreter.cpp"; sourceTree = ""; }; + 2491E935A0E23ED9309DF4C5E517694E /* FlexColorPicker.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FlexColorPicker.release.xcconfig; sourceTree = ""; }; + 2592765ADE2B014E4E4341340C29238A /* StaticDataTableViewController.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = StaticDataTableViewController.release.xcconfig; sourceTree = ""; }; + 28A378F9A01525E97149ABB8DCA5B1CC /* event.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = event.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/event.cpp"; sourceTree = ""; }; + 2B3DFF34646C16CCCF89F9B271E9F3C5 /* MetaWear-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MetaWear-prefix.pch"; sourceTree = ""; }; + 2B682398687C85519B90ED18DBEE7951 /* settings.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = settings.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/settings.cpp"; sourceTree = ""; }; + 2B7CB030AD099F3C8A3F365D79A48586 /* cbindings.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = cbindings.swift; path = "MetaWear/MetaWear-SDK-Cpp/bindings/swift/cbindings.swift"; sourceTree = ""; }; + 2B99CC70D3AFA59FB6FE09F278637FBC /* proximity_tsl2671.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = proximity_tsl2671.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/proximity_tsl2671.cpp"; sourceTree = ""; }; + 2DB10B9B88AEAF7203CF4E5E6BCED7DC /* led.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = led.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/led.cpp"; sourceTree = ""; }; + 2F47F4AA73ACEAC9FDA41D36C0332414 /* dfu_operations.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = dfu_operations.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_operations.cpp"; sourceTree = ""; }; + 30031551201F975A50370A70C7E5A533 /* MetaWear-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "MetaWear-Info.plist"; sourceTree = ""; }; 30792539D3A4F7C948568EB5F1CD1B91 /* Pods-MusicalCaneGame-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-MusicalCaneGame-acknowledgements.markdown"; sourceTree = ""; }; - 311E32021E8602317EB6D1575470819D /* MBLMacAddressFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMacAddressFormat.m; path = MetaWear/Internal/Core/MBLMacAddressFormat.m; sourceTree = ""; }; - 314B0529C31F19362B7AD83D00A099B7 /* MBLAccelerometerBoschAxisReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschAxisReadyEvent.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschAxisReadyEvent.m; sourceTree = ""; }; - 314B82F710899A1A23F5558B1E07BC30 /* BFTask+Exceptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "BFTask+Exceptions.h"; path = "Bolts/Common/BFTask+Exceptions.h"; sourceTree = ""; }; - 31EB4B1CA22089606877D26BE732188B /* MBLAmbientLight.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAmbientLight.h; path = MetaWear/Classes/Modules/AmbientLight/MBLAmbientLight.h; sourceTree = ""; }; - 31F2FE25B77174C58D106A70256387EB /* MBLBarometerBoschPeriodicPressureEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBarometerBoschPeriodicPressureEvent.h; path = MetaWear/Internal/Modules/Barometer/BarometerBosch/MBLBarometerBoschPeriodicPressureEvent.h; sourceTree = ""; }; - 34088EF7AE33D968FAB900636386D40C /* MBLTimer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLTimer.m; path = MetaWear/Classes/Modules/Timer/MBLTimer.m; sourceTree = ""; }; - 3415A4F0C188A771B1C86C144FE2C83F /* Statement.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Statement.swift; path = Sources/SQLite/Core/Statement.swift; sourceTree = ""; }; - 3504F10AAE9AFDB28FCB395022D5FE8C /* MBProgressHUD.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = MBProgressHUD.m; sourceTree = ""; }; - 3518CBD6D03CE59AEF5ED8F8A1AAB9BE /* MBLAccelerometerOrientationEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerOrientationEvent.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerOrientationEvent.h; sourceTree = ""; }; - 3546FE1448811DA0824B98448DE651B1 /* MBLTemperature.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLTemperature.m; path = MetaWear/Classes/Modules/Temperature/MBLTemperature.m; sourceTree = ""; }; - 355BD6A3989345E5BAE24648E1B93CA0 /* MBLQuaternionData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLQuaternionData.m; path = MetaWear/Classes/Modules/SensorFusion/MBLQuaternionData.m; sourceTree = ""; }; - 35847D051FF4AC1EA26B080D0C468C99 /* MBLEntityEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLEntityEvent+Private.h"; path = "MetaWear/Internal/Core/MBLEntityEvent+Private.h"; sourceTree = ""; }; - 35AA2A32130BF6780B993286A8E753CA /* Expression.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Expression.swift; path = Sources/SQLite/Typed/Expression.swift; sourceTree = ""; }; - 362DE09F372E1F53540DDE7687212B9C /* MBLGPIOPinChangeEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGPIOPinChangeEvent.m; path = MetaWear/Internal/Modules/GPIO/MBLGPIOPinChangeEvent.m; sourceTree = ""; }; - 374FAE1C230EFE649798C56C0E26D6E7 /* FastCoding-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FastCoding-dummy.m"; sourceTree = ""; }; - 3754406911E8EE9E7F3A41663E738787 /* MBLRMSAccelerometerData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLRMSAccelerometerData.m; path = MetaWear/Classes/Modules/Accelerometer/MBLRMSAccelerometerData.m; sourceTree = ""; }; - 376008DE59AE2BE57F75A4D045ADCBDB /* MBLSerial.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLSerial.h; path = MetaWear/Classes/Modules/Serial/MBLSerial.h; sourceTree = ""; }; - 3809ADBAC12D7B7A5F2BBDA7627FCEF2 /* SQLite.swift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SQLite.swift.modulemap; sourceTree = ""; }; - 38AC511C52A3160D8BFA36D301F88345 /* MBLEulerAngleData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLEulerAngleData.m; path = MetaWear/Classes/Modules/SensorFusion/MBLEulerAngleData.m; sourceTree = ""; }; - 38AFE3A959AC36D6E49E405E5F9C6B1C /* BFTaskCompletionSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFTaskCompletionSource.h; path = Bolts/Common/BFTaskCompletionSource.h; sourceTree = ""; }; - 38CFCDB0514EBAAEF4CEE12D05EE8109 /* mma8452q.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = mma8452q.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/mma8452q.h; sourceTree = ""; }; - 38F0F7A8A8D5D19437156CA5EE554129 /* MBLSPIData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLSPIData.h; path = MetaWear/Classes/Modules/Serial/MBLSPIData.h; sourceTree = ""; }; - 3900077A4790606E2800E23E5A2D5B1C /* Collation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Collation.swift; path = Sources/SQLite/Typed/Collation.swift; sourceTree = ""; }; - 396C92EDB59F8462AA3C5CF4A773E86A /* MBLANCSEventData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLANCSEventData+Private.h"; path = "MetaWear/Internal/Modules/ANCS/MBLANCSEventData+Private.h"; sourceTree = ""; }; + 31224639020F2F283B2541B95F80CD64 /* StaticDataTableViewController-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "StaticDataTableViewController-prefix.pch"; sourceTree = ""; }; + 31C846A5D44EB3A55B8C787DC3D91CCF /* ControlWithThumbView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlWithThumbView.swift; path = FlexColorPicker/Classes/Controls/ControlWithThumbView.swift; sourceTree = ""; }; + 33D59C5EE9504CAE85DD5EC3A8B2619D /* PRTween.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PRTween.release.xcconfig; sourceTree = ""; }; + 3505FB4027267F44B467A1CE3189BE2A /* PRTween.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PRTween.m; path = lib/PRTween.m; sourceTree = ""; }; + 3589746F3729736D14CFCA7C05CDF29A /* macro.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = macro.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/macro.cpp"; sourceTree = ""; }; 39A6402C9A55218C24EEBE89F696397F /* Pods-MusicalCaneGame-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-MusicalCaneGame-acknowledgements.plist"; sourceTree = ""; }; - 39D64BE10B561A0D34719CA9330EB32E /* MBLGyroBMI160PackedDataReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGyroBMI160PackedDataReadyEvent.h; path = MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160PackedDataReadyEvent.h; sourceTree = ""; }; - 3A0C1066A28DFD968093094A4002CDC2 /* MBLConversion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLConversion.h; path = MetaWear/Internal/Core/MBLConversion.h; sourceTree = ""; }; - 3A8C11505635DEA31ECB90490AD1B7C0 /* MBLI2CData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLI2CData+Private.h"; path = "MetaWear/Internal/Modules/Serial/MBLI2CData+Private.h"; sourceTree = ""; }; - 3AB44C67614744596C398BB3B0F6913A /* MetaWear.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MetaWear.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 3ACCB93D2A72146FE33631D032901428 /* MBLLogging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLLogging.h; path = MetaWear/Internal/Modules/Logging/MBLLogging.h; sourceTree = ""; }; - 3B069E8C2577A06891520F8052F65562 /* MBLAccelerometerBoschAxisReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschAxisReadyEvent.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschAxisReadyEvent.h; sourceTree = ""; }; - 3BC4C89BFE4515AEAFA90A8F0A2DB780 /* MBLEntityModule.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLEntityModule.h; path = MetaWear/Classes/Core/MBLEntityModule.h; sourceTree = ""; }; - 3C4F3EEAA0ADC98A3D8086E8AA82416C /* MBLLoggingV0.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLLoggingV0.h; path = MetaWear/Internal/Modules/Logging/MBLLoggingV0.h; sourceTree = ""; }; - 3C6E172F7AFAEC647876724C2CDCD8E2 /* Bolts-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Bolts-dummy.m"; sourceTree = ""; }; - 3D1007461EE807A8FADC1771B6E82285 /* MBProgressHUD-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "MBProgressHUD-Info.plist"; sourceTree = ""; }; - 3D4398BE85C107FC9E87B95339D7DECD /* MBLEulerAngleData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLEulerAngleData.h; path = MetaWear/Classes/Modules/SensorFusion/MBLEulerAngleData.h; sourceTree = ""; }; - 3DEBDB14BDA140D4AF5011F56E278A27 /* Bolts-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Bolts-prefix.pch"; sourceTree = ""; }; - 3F5F92185806E08CE8B628A488ACF9DE /* MBLAccelerometerBoschFlatFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschFlatFormat.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFlatFormat.m; sourceTree = ""; }; - 3F8D2F802D75DFA0F0B9B216784D8953 /* MBLFirmwareUpdateInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLFirmwareUpdateInfo.h; path = MetaWear/Classes/Core/MBLFirmwareUpdateInfo.h; sourceTree = ""; }; - 413CB9A1D4E013A9F23D12B5BC1A5D43 /* UIImageViewExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIImageViewExtension.swift; path = FlexColorPicker/Classes/Utilities/UIImageViewExtension.swift; sourceTree = ""; }; - 4196509A0F6F6008BEA13E7494AE5C80 /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.m; path = MetaWear/Internal/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.m; sourceTree = ""; }; - 427AC7DC4569033439CABA2A30EC3326 /* AdjustedHitBoxColorControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AdjustedHitBoxColorControl.swift; path = FlexColorPicker/Classes/Controls/AdjustedHitBoxColorControl.swift; sourceTree = ""; }; - 42C1C7FC4D76208F93B744123BD11F49 /* Value.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Value.swift; path = Sources/SQLite/Core/Value.swift; sourceTree = ""; }; - 42E7ABDEEF2B747C41A103067522FC2D /* MBLLoggingV0.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLLoggingV0.m; path = MetaWear/Internal/Modules/Logging/MBLLoggingV0.m; sourceTree = ""; }; - 43968FC5841B33AC860F8B17B9CA2E76 /* Bolts.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Bolts.debug.xcconfig; sourceTree = ""; }; - 43A5D2835F778AEC4A8D236902ADAF29 /* MBLTestDebug.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLTestDebug.m; path = MetaWear/Internal/Modules/TestDebug/MBLTestDebug.m; sourceTree = ""; }; - 43A8C9E3945A6C2788CB41E514EEA131 /* MBLRGBData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLRGBData.m; path = MetaWear/Classes/Modules/Photometer/MBLRGBData.m; sourceTree = ""; }; - 44131CFFCDE00E71F5EACDF06483240F /* MBLBarometerBME280.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBarometerBME280.h; path = MetaWear/Classes/Modules/Barometer/BarometerBosch/BarometerBME280/MBLBarometerBME280.h; sourceTree = ""; }; - 4443E63922CECE498D2F090F518F1509 /* MetaWearPrivate-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MetaWearPrivate-umbrella.h"; sourceTree = ""; }; - 4466835466E43CAEA302DA6589EA68F8 /* MBLEulerFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLEulerFormat.h; path = MetaWear/Internal/Modules/SensorFusion/MBLEulerFormat.h; sourceTree = ""; }; - 4466877CF34DEA4079247DFB20452293 /* MBLQuaternionData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLQuaternionData.h; path = MetaWear/Classes/Modules/SensorFusion/MBLQuaternionData.h; sourceTree = ""; }; + 3AA4B180B473FDCCAA0F33EDC10B353E /* sensor_fusion.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = sensor_fusion.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/sensor_fusion.cpp"; sourceTree = ""; }; + 3B48995017BA31F28C04293A293DB8B0 /* accelerometer_mma8452q.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = accelerometer_mma8452q.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_mma8452q.cpp"; sourceTree = ""; }; + 3EA827C8B3D6F7A27497CC460A903E67 /* MetaWear.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MetaWear.release.xcconfig; sourceTree = ""; }; + 3F0F495A31ECF7DBEEB5653F543F0FF2 /* Schema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = Sources/SQLite/Typed/Schema.swift; sourceTree = ""; }; + 406C98AC09D595E5C506DE76BF364909 /* StaticDataTableViewController-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "StaticDataTableViewController-umbrella.h"; sourceTree = ""; }; + 41E0C85C4A4ABE0F68AAF0204AA763F8 /* Coding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Coding.swift; path = Sources/SQLite/Typed/Coding.swift; sourceTree = ""; }; + 41F889C88E2EAA1759E630D7B46E37AF /* task.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = task.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/task.cpp"; sourceTree = ""; }; + 4359429DE1914ED1F6EAEE419A29AF4B /* Bolts-Swift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Bolts-Swift-Info.plist"; sourceTree = ""; }; + 437E87C04ED10A10DE2D29A5C9F52D66 /* AggregateFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AggregateFunctions.swift; path = Sources/SQLite/Typed/AggregateFunctions.swift; sourceTree = ""; }; + 44850702D275D1B542895C838EDE8E50 /* SQLite.swift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SQLite.swift.debug.xcconfig; sourceTree = ""; }; 448E2B4D025708620E619D128E766E36 /* Pods-MusicalCaneGame-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-MusicalCaneGame-dummy.m"; sourceTree = ""; }; - 448ECF74A645B4FA12173EB17977FD37 /* MBLTemperatureV0.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLTemperatureV0.m; path = MetaWear/Internal/Modules/Temperature/MBLTemperatureV0.m; sourceTree = ""; }; - 44B4B3FD98CDD35B0B752E3160CA04B3 /* Bolts.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Bolts.m; path = Bolts/Common/Bolts.m; sourceTree = ""; }; - 4519EAF79C77387F18804362AB896741 /* MBLDataProcessor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLDataProcessor.m; path = MetaWear/Internal/Modules/DataProcessor/MBLDataProcessor.m; sourceTree = ""; }; - 462DD61F30926FABAAD6EA3D27791201 /* MBLProximity.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLProximity.m; path = MetaWear/Classes/Modules/Proximity/MBLProximity.m; sourceTree = ""; }; - 465EF3F6218763ECC68FD764A9551DA5 /* LimitedGestureCircleView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LimitedGestureCircleView.swift; path = FlexColorPicker/Classes/Views/LimitedGestureCircleView.swift; sourceTree = ""; }; + 4696B4A78EB5B5B2019A21FEF3C142FB /* AdjustedHitBoxColorControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AdjustedHitBoxColorControl.swift; path = FlexColorPicker/Classes/Controls/AdjustedHitBoxColorControl.swift; sourceTree = ""; }; 478174D0C87B9553375A4A8103192D96 /* Pods-MusicalCaneGame-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-MusicalCaneGame-umbrella.h"; sourceTree = ""; }; - 4795D991502F3682F21E8D2935999466 /* FastCoding.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FastCoding.debug.xcconfig; sourceTree = ""; }; - 47D66A0D6964C883FD711DA03207DC6F /* PaletteAwareScrollView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PaletteAwareScrollView.swift; path = FlexColorPicker/Classes/Views/PaletteAwareScrollView.swift; sourceTree = ""; }; - 47D7B95DD4B4EA43332240D4AFBC5C9B /* MBLProximityTSL2671.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLProximityTSL2671.m; path = MetaWear/Classes/Modules/Proximity/ProximityTSL2671/MBLProximityTSL2671.m; sourceTree = ""; }; - 47FE082C207AA18A150F1D2E98BBC37D /* Schema.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Schema.swift; path = Sources/SQLite/Typed/Schema.swift; sourceTree = ""; }; - 48B07B0B83A11EC07DF4B3E6582A952A /* MBLMockUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMockUtils.h; path = MetaWear/Internal/Mocks/MBLMockUtils.h; sourceTree = ""; }; - 4924598DFBB638C24E440E1CE354CBCB /* MBLNumericData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLNumericData.m; path = MetaWear/Classes/Core/MBLNumericData.m; sourceTree = ""; }; - 493E9D78B13733C59AB3A986CB697840 /* MetaWearPrivate.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MetaWearPrivate.release.xcconfig; sourceTree = ""; }; - 49DA9CBC33AA2FDF6359C8FD3F306800 /* MBLAccelerometerBoschLowOrHighGEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBoschLowOrHighGEvent+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschLowOrHighGEvent+Private.h"; sourceTree = ""; }; - 4A521C64917321A402EE237FF16FD9B0 /* MetaWear.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MetaWear.h; path = MetaWear/Classes/MetaWear.h; sourceTree = ""; }; - 4ACD94175F05C0E29F06F1928D1B2923 /* StaticDataTableViewController-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "StaticDataTableViewController-dummy.m"; sourceTree = ""; }; - 4AE72B7641A8DE28BB231324BA8FA0C9 /* MBLCorrectedFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLCorrectedFormat.m; path = MetaWear/Internal/Modules/SensorFusion/MBLCorrectedFormat.m; sourceTree = ""; }; - 4BB39B281AA329E7B6D910316E475CB1 /* SQLite-Bridging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "SQLite-Bridging.h"; path = "Sources/SQLiteObjc/include/SQLite-Bridging.h"; sourceTree = ""; }; - 4C15691C1FD31BFF5F8FAFD44482CA17 /* MBLAccelerometerBoschFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschFormat.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFormat.h; sourceTree = ""; }; - 4C2249EBCE5DF74C7202C4C1603B5C78 /* MBLGyroData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGyroData.h; path = MetaWear/Classes/Modules/Gyro/MBLGyroData.h; sourceTree = ""; }; - 4CC217CF9EA007AD52303A46616501F0 /* PRTween-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PRTween-umbrella.h"; sourceTree = ""; }; - 4D957451FBD0710F6B80E2099435B1C6 /* FlexColorPicker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FlexColorPicker.h; path = FlexColorPicker/Classes/FlexColorPicker.h; sourceTree = ""; }; - 4DD64AB34CC0A56FD03310D59BD66415 /* MBLBarometerBoschPeriodicPressureEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBarometerBoschPeriodicPressureEvent.m; path = MetaWear/Internal/Modules/Barometer/BarometerBosch/MBLBarometerBoschPeriodicPressureEvent.m; sourceTree = ""; }; - 4DD64C1100F3E64306313F24E970E06C /* MBLModuleMock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLModuleMock.h; path = MetaWear/Internal/Mocks/MBLModuleMock.h; sourceTree = ""; }; - 4E1E7DEA33754A4BDE312E7F9208C89F /* MBLMagnetometerData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLMagnetometerData+Private.h"; path = "MetaWear/Internal/Modules/Magnetometer/MBLMagnetometerData+Private.h"; sourceTree = ""; }; - 4E38AEA2BBA3C0224D73CD1875E2B759 /* FlexColorPicker.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FlexColorPicker.release.xcconfig; sourceTree = ""; }; - 4E97D61EA17F90FA1A96C5EA492CA4FB /* MBLBluetoothCentral.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBluetoothCentral.h; path = MetaWear/Internal/Mocks/MBLBluetoothCentral.h; sourceTree = ""; }; - 4FC26A49844C73557693D346B633ECF5 /* MBLMagnetometerBMM150.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMagnetometerBMM150.m; path = MetaWear/Classes/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150.m; sourceTree = ""; }; - 50B863789CB70C7BB079677C237AD2B1 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMagnetometerBMM150PeriodicMagneticFieldEvent.h; path = MetaWear/Internal/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150PeriodicMagneticFieldEvent.h; sourceTree = ""; }; - 513FAF97F4FE15694C4CF4A8304BBEF3 /* MBLGPIO.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGPIO.h; path = MetaWear/Classes/Modules/GPIO/MBLGPIO.h; sourceTree = ""; }; - 51983FC1E94C3A7B3263DD06D3CCB519 /* MBLAccelerometerBoschOrientationFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschOrientationFormat.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschOrientationFormat.h; sourceTree = ""; }; - 519EE35C72315D1A7AADC923C91B38E7 /* MBLExternalThermistor1.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLExternalThermistor1.h; path = MetaWear/Internal/Modules/Temperature/MBLExternalThermistor1.h; sourceTree = ""; }; - 51E77D088B0EFA67C576F729BE56D26F /* Connection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Connection.swift; path = Sources/SQLite/Core/Connection.swift; sourceTree = ""; }; - 52348E26326B74D99A9556A7F07D4FA4 /* ColorControlContentView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorControlContentView.swift; path = FlexColorPicker/Classes/Views/ColorControlContentView.swift; sourceTree = ""; }; - 532D7FCACBDEC3A993ACD5007C5C63B0 /* MBLCategoryLoader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLCategoryLoader.h; path = MetaWear/Internal/Categories/MBLCategoryLoader.h; sourceTree = ""; }; - 5381E2D2DD1B9D824DD465B2CF527DAB /* MBLGPIOPin.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGPIOPin.m; path = MetaWear/Classes/Modules/GPIO/MBLGPIOPin.m; sourceTree = ""; }; - 5391ECE3ABD3B21D5B420350C96853A3 /* MBLMetaWear.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMetaWear.h; path = MetaWear/Classes/Core/MBLMetaWear.h; sourceTree = ""; }; - 5447D64353ADF313B6DDA3764B0AA4ED /* MBLMechanicalSwitch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMechanicalSwitch.h; path = MetaWear/Classes/Modules/MechanicalSwitch/MBLMechanicalSwitch.h; sourceTree = ""; }; - 557E2DBC953B749080CCF587EB527F41 /* SQLite.swift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SQLite.swift-umbrella.h"; sourceTree = ""; }; - 5593CCBED8E4AE15625FF3ACD2A666C7 /* MBLANCSEventData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLANCSEventData.m; path = MetaWear/Classes/Modules/ANCS/MBLANCSEventData.m; sourceTree = ""; }; - 55E0C2D944995BB40CFA9BD4DF56E8EC /* MBLMagnetometerData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMagnetometerData.h; path = MetaWear/Classes/Modules/Magnetometer/MBLMagnetometerData.h; sourceTree = ""; }; - 567F029623C3C2A10DC63BEC9ED354CA /* MBLMagnetometerBMM150Format.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMagnetometerBMM150Format.m; path = MetaWear/Internal/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150Format.m; sourceTree = ""; }; - 56864443F16243B0215C7D7BBA02BF12 /* MBLTimer+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLTimer+Private.h"; path = "MetaWear/Internal/Modules/Timer/MBLTimer+Private.h"; sourceTree = ""; }; - 56CE0C94F84E1FF8FDAF0132715EE59D /* MBLGyroBMI160DataReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGyroBMI160DataReadyEvent.m; path = MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160DataReadyEvent.m; sourceTree = ""; }; - 579F7BDE884513135251D390A9416BBE /* MBLANCS.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLANCS.m; path = MetaWear/Classes/Modules/ANCS/MBLANCS.m; sourceTree = ""; }; - 5865681E3AF1BA1C5A344C7FAEADCD6E /* MBLDependentData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLDependentData.h; path = MetaWear/Internal/Core/MBLDependentData.h; sourceTree = ""; }; - 58D0EAE6159180C30086D9739F578720 /* Coding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Coding.swift; path = Sources/SQLite/Typed/Coding.swift; sourceTree = ""; }; - 595E3AE5886C8CFBDE5B91E71DF980BD /* MBLEntityEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLEntityEvent.h; path = MetaWear/Classes/Core/MBLEntityEvent.h; sourceTree = ""; }; - 59B5866AFB868B2385488D9FF72A80D8 /* MBLBitmaskEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBitmaskEvent.m; path = MetaWear/Internal/Modules/SensorFusion/MBLBitmaskEvent.m; sourceTree = ""; }; - 5A1B6E114D5CB12C862036963DCB2390 /* MBLAccelerometer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometer.m; path = MetaWear/Classes/Modules/Accelerometer/MBLAccelerometer.m; sourceTree = ""; }; - 5B024B6DFDED940969EFF42A43655986 /* MBLAccelerometerOrientationEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerOrientationEvent.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerOrientationEvent.m; sourceTree = ""; }; - 5B13756AF4593D9371410055A4AE2417 /* BFTaskCompletionSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFTaskCompletionSource.m; path = Bolts/Common/BFTaskCompletionSource.m; sourceTree = ""; }; - 5B86A2EA02A200B150829527A34D0C29 /* MBLDownloadOnlyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLDownloadOnlyEvent.m; path = MetaWear/Internal/Core/MBLDownloadOnlyEvent.m; sourceTree = ""; }; - 5BFC3E767B602E9CA2FA9B76A93CFEAA /* FlexColorPicker-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FlexColorPicker-Info.plist"; sourceTree = ""; }; - 5C0E0758C2BBAC987D1296921D92C489 /* SQLite.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SQLite.h; path = Sources/SQLite/SQLite.h; sourceTree = ""; }; - 5C7F2255FF56AF376C85585754EF2C3A /* MBLFirmwareUpdateManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLFirmwareUpdateManager.h; path = MetaWear/Internal/DFU/MBLFirmwareUpdateManager.h; sourceTree = ""; }; - 5CC113B94F2B618EE4AA6709AF7E01C7 /* Bolts-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Bolts-Info.plist"; sourceTree = ""; }; - 5D1777824CD3B762DAC2AFDF780D0A21 /* HSBColor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HSBColor.swift; path = FlexColorPicker/Classes/HSBColor.swift; sourceTree = ""; }; - 5EFE1999F17421FBBC0203397DD7308E /* MBLTriggeredRead.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLTriggeredRead.h; path = MetaWear/Internal/Core/MBLTriggeredRead.h; sourceTree = ""; }; - 5F05E3F8AB2E722ADB3A3663D0DE873B /* MBProgressHUD-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MBProgressHUD-umbrella.h"; sourceTree = ""; }; - 5F5B2380B642EC90ACB0655B0A740AAC /* MBLGyro.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGyro.m; path = MetaWear/Classes/Modules/Gyro/MBLGyro.m; sourceTree = ""; }; - 5FC1A99D023D267E648A3B2CCD8CC0F7 /* MBLStringData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLStringData.m; path = MetaWear/Classes/Core/MBLStringData.m; sourceTree = ""; }; - 5FC5822E40E89D5C92D574C41A031395 /* MBLAccelerometerBoschFlatData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschFlatData.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFlatData.h; sourceTree = ""; }; - 61EBB4660D809D8033457C2CE80411B9 /* MBLBarometerBME280.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBarometerBME280.m; path = MetaWear/Classes/Modules/Barometer/BarometerBosch/BarometerBME280/MBLBarometerBME280.m; sourceTree = ""; }; - 62BD501B622AE2197A8251EBEBC98B30 /* MBProgressHUD.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MBProgressHUD.release.xcconfig; sourceTree = ""; }; - 63B6032E50F1902598BCFDCBF410C4DB /* MetaWearPrivate-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MetaWearPrivate-prefix.pch"; sourceTree = ""; }; - 63F79A6649FBFB5574186379DCD1D421 /* MBLANCS.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLANCS.h; path = MetaWear/Classes/Modules/ANCS/MBLANCS.h; sourceTree = ""; }; - 64CDB650D726216D211F98C83B8AEB07 /* PRTween-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "PRTween-Info.plist"; sourceTree = ""; }; - 654770BD0B9DFE0978C88E8FA6D5AE04 /* BFTask+MBLPrivate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "BFTask+MBLPrivate.m"; path = "MetaWear/Internal/Categories/BFTask+MBLPrivate.m"; sourceTree = ""; }; - 65D6DC10F5E74FFA08C8CED7FFFD778C /* MBLAccelerometerBoschFlatData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschFlatData.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFlatData.m; sourceTree = ""; }; - 66413B269210BA611B909CE76A0081F7 /* MBLDataProcessor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLDataProcessor.h; path = MetaWear/Internal/Modules/DataProcessor/MBLDataProcessor.h; sourceTree = ""; }; - 666047892D4382C05D1CA2A8AD020509 /* MBLCategoryLoader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLCategoryLoader.m; path = MetaWear/Internal/Categories/MBLCategoryLoader.m; sourceTree = ""; }; - 66E71F2FFA4B67A171FF369570E25CDA /* FlexColorPicker.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FlexColorPicker.modulemap; sourceTree = ""; }; - 6719B0DAAFC53A5D67AB989C9C97A924 /* ColorSliderDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorSliderDelegate.swift; path = FlexColorPicker/Classes/ControlDelegates/ColorSliderDelegate.swift; sourceTree = ""; }; - 6723B5F56E66FCC63A664969CF24F4DC /* PRTween.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PRTween.h; path = lib/PRTween.h; sourceTree = ""; }; - 67ABBB9175C1AB274D0D7EAA75F73CE3 /* MBLConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLConstants.m; path = MetaWear/Classes/Core/MBLConstants.m; sourceTree = ""; }; - 67E7ECC3E54031D450010ADCF4BE7A02 /* MBLBarometer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBarometer.m; path = MetaWear/Classes/Modules/Barometer/MBLBarometer.m; sourceTree = ""; }; - 67FC590E9E7EF5DA3862AFD78F294140 /* SQLite.swift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SQLite.swift-Info.plist"; sourceTree = ""; }; - 68755AC626C33567BB3E422E830BFF81 /* MBLConversion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLConversion.m; path = MetaWear/Internal/Core/MBLConversion.m; sourceTree = ""; }; - 689DA3C1690AA04AD8F0B525102106FB /* MBLGPIOPinChangeEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGPIOPinChangeEvent.h; path = MetaWear/Internal/Modules/GPIO/MBLGPIOPinChangeEvent.h; sourceTree = ""; }; - 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - 68DEBCDB3540DF8E8A66FBD60AA6EC1D /* MBLAccelerometerMMA8452Q.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerMMA8452Q.m; path = MetaWear/Classes/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452Q.m; sourceTree = ""; }; - 69873ABB652364D99E9A6C4958E48A7B /* StaticDataTableViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = StaticDataTableViewController.h; sourceTree = ""; }; - 6A1E8DAD74C3585D5AF1D9889AB1298C /* MBLGyroData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGyroData.m; path = MetaWear/Classes/Modules/Gyro/MBLGyroData.m; sourceTree = ""; }; - 6A32380E9FDE7BF474147BE27EF6EA33 /* MBLAccelerometerBoschOrientationEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschOrientationEvent.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschOrientationEvent.h; sourceTree = ""; }; - 6A3A5964E423BCF12F97938C3CE21151 /* MBLNeopixelStrand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLNeopixelStrand.m; path = MetaWear/Classes/Modules/Neopixel/MBLNeopixelStrand.m; sourceTree = ""; }; - 6A43CC85B18E8ACDE0E384BBD649438C /* Setter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Setter.swift; path = Sources/SQLite/Typed/Setter.swift; sourceTree = ""; }; - 6C76C0FCB90D1002A9C4A440C1A2AA92 /* PRTween.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PRTween.debug.xcconfig; sourceTree = ""; }; - 6C9E7AAB9EDEB14A11FC03AB7D891254 /* MBLGPIO+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLGPIO+Private.h"; path = "MetaWear/Internal/Modules/GPIO/MBLGPIO+Private.h"; sourceTree = ""; }; - 6E243FEF6D81DE5AFC9EBD3BDA3C420C /* MBLNumericData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLNumericData+Private.h"; path = "MetaWear/Internal/Core/MBLNumericData+Private.h"; sourceTree = ""; }; + 47834DBA79AF16C25F6D7EA5E5155B13 /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = Sources/BoltsSwift/Errors.swift; sourceTree = ""; }; + 4855729C74F392B162E88C5A7F2DCEC2 /* CustomFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomFunctions.swift; path = Sources/SQLite/Typed/CustomFunctions.swift; sourceTree = ""; }; + 4904F9E5929463BAFB7240A014D562EF /* neopixel.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = neopixel.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/neopixel.cpp"; sourceTree = ""; }; + 4C7E47F325908076A46464074F516599 /* threadpool.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = threadpool.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/threadpool.cpp"; sourceTree = ""; }; + 4DD70463C6C75069EC322EC78E9B74EF /* CoreFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CoreFunctions.swift; path = Sources/SQLite/Typed/CoreFunctions.swift; sourceTree = ""; }; + 4DEDCD99D3FF6C87DA7A9228B2EA1B73 /* Setter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Setter.swift; path = Sources/SQLite/Typed/Setter.swift; sourceTree = ""; }; + 4E0DEB45E3FBA4102D9F9FB1D8E82D90 /* MetaWearScanner.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MetaWearScanner.swift; path = MetaWear/Core/MetaWearScanner.swift; sourceTree = ""; }; + 4E361A5F54DAAE628EE9C57E66FB6063 /* file_operations.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = file_operations.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/file_operations.cpp"; sourceTree = ""; }; + 50BDC1CDDC48EE3D660BD7653DA1A8B5 /* MetaWear-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MetaWear-umbrella.h"; sourceTree = ""; }; + 5349A2FBCECBAF0D2A07BF2B4B1861A7 /* MBProgressHUD.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MBProgressHUD.release.xcconfig; sourceTree = ""; }; + 5741ABB2DC93CE21CD2A606D5DEEA17C /* RectangularHSBPaletteDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RectangularHSBPaletteDelegate.swift; path = FlexColorPicker/Classes/ControlDelegates/RectangularHSBPaletteDelegate.swift; sourceTree = ""; }; + 590BAB70520695F7005DBB2221F72974 /* ibeacon.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = ibeacon.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/ibeacon.cpp"; sourceTree = ""; }; + 59EA51B0D70CEB18187D969528EF0418 /* MBProgressHUD-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "MBProgressHUD-dummy.m"; sourceTree = ""; }; + 5CC2C0DCF05FC714271C90C86A6877FC /* dfu_utility.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = dfu_utility.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/dfu_utility.cpp"; sourceTree = ""; }; + 619D18BEE833C4348EAF940808AA2B11 /* SQLite-Bridging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "SQLite-Bridging.m"; path = "Sources/SQLiteObjc/SQLite-Bridging.m"; sourceTree = ""; }; + 61AB588063CB884AA3519F769BE6EC82 /* Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Foundation.swift; path = Sources/SQLite/Foundation.swift; sourceTree = ""; }; + 650F4F40CE2E099A10834D340BBD9EDE /* MetaWear-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "MetaWear-dummy.m"; sourceTree = ""; }; + 65CD4D32CCEF7CD1945A9206364F5D59 /* anonymous_datasignal.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = anonymous_datasignal.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/anonymous_datasignal.cpp"; sourceTree = ""; }; + 68270A8D2FCE48DD4B73F8783B5E0F17 /* ColorSliderControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorSliderControl.swift; path = FlexColorPicker/Classes/Controls/ColorSliderControl.swift; sourceTree = ""; }; + 6830BF747190EDBF2EB01106C0C94705 /* Bridging.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bridging.swift; path = MetaWear/Core/Bridging.swift; sourceTree = ""; }; + 68A07C8AA447D9D1F965F51BFEA3D3B2 /* MBProgressHUD-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MBProgressHUD-umbrella.h"; sourceTree = ""; }; + 68C951AAE97E1F47CDEDF6CCF3B94C2A /* Task+Delay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Task+Delay.swift"; path = "Sources/BoltsSwift/Task+Delay.swift"; sourceTree = ""; }; + 6C18FBB6DA4349BD98E91AC4F8B2CC45 /* MBProgressHUD-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MBProgressHUD-prefix.pch"; sourceTree = ""; }; + 6CC590A92CBE7E54F981E383DAB2F33D /* PRTween-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "PRTween-Info.plist"; sourceTree = ""; }; + 6DCABDA1D6ACE795F49425A95926630A /* PRTween.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PRTween.debug.xcconfig; sourceTree = ""; }; 6E87F128D99E2CC3AFB7243CE45DE0C4 /* PRTween.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PRTween.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 6EDC6817E50BBE358090BE6382A9D43A /* MBLSerial.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLSerial.m; path = MetaWear/Classes/Modules/Serial/MBLSerial.m; sourceTree = ""; }; 6F06C6D2A37B9901E2E3277EAA264539 /* StaticDataTableViewController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StaticDataTableViewController.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 6F276868A47C5827372AA153634270CD /* MBLOrientationData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLOrientationData.m; path = MetaWear/Classes/Modules/Accelerometer/MBLOrientationData.m; sourceTree = ""; }; - 70662CA035EC8936750C436C9EEA15B8 /* CircleShapedView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CircleShapedView.swift; path = FlexColorPicker/Classes/Views/CircleShapedView.swift; sourceTree = ""; }; - 7095B1A9FFD67603BD83BD4F313E1E8E /* PRTween.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PRTween.release.xcconfig; sourceTree = ""; }; - 710C8C193172A27E175ED44AD3F04CDD /* MBLDependentData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLDependentData.m; path = MetaWear/Internal/Core/MBLDependentData.m; sourceTree = ""; }; - 7114D8A31D2986FB66EF6D7AE023531B /* MBLNonVolatileState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLNonVolatileState.h; path = MetaWear/Internal/Core/MBLNonVolatileState.h; sourceTree = ""; }; - 71CB5DA203DD44720C6516AE4751BDF8 /* MBLAccelerometerAxisReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerAxisReadyEvent.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerAxisReadyEvent.m; sourceTree = ""; }; - 72290EA994E18E954E95E198E4CF8270 /* MBLTemperatureV1.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLTemperatureV1.m; path = MetaWear/Internal/Modules/Temperature/MBLTemperatureV1.m; sourceTree = ""; }; - 72F8368AD145B7E0B2F4F356CD3EF20C /* MBLModule.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLModule.m; path = MetaWear/Classes/Core/MBLModule.m; sourceTree = ""; }; - 73446BDE690FF38C64E2D46A9E471DA0 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CoreBluetooth.framework; sourceTree = DEVELOPER_DIR; }; - 73950693CB69C144751AB0335D5AF000 /* MBLBarometerBosch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBarometerBosch.m; path = MetaWear/Classes/Modules/Barometer/BarometerBosch/MBLBarometerBosch.m; sourceTree = ""; }; + 72F91017E90ACD4FCE83A3485695C412 /* colordetector_tcs34725.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = colordetector_tcs34725.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/colordetector_tcs34725.cpp"; sourceTree = ""; }; + 73ACA690A071AA3BE5E5B9F95806F095 /* MBProgressHUD.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = MBProgressHUD.modulemap; sourceTree = ""; }; 741F9D3943FF7542B04631B29216270F /* FlexColorPicker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FlexColorPicker.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 74B21379AD8E4BA85136D6EA4099C510 /* MBLModuleInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLModuleInfo.h; path = MetaWear/Internal/Core/MBLModuleInfo.h; sourceTree = ""; }; - 74CC7720DE0EECC6FADF0ADA2BBB29BA /* MBLAccelerometerBoschPackedDataReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschPackedDataReadyEvent.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschPackedDataReadyEvent.h; sourceTree = ""; }; - 75A53299EEC86ABF9064680EBDC08974 /* ColorPickerController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPickerController.swift; path = FlexColorPicker/Classes/ColorPickerController.swift; sourceTree = ""; }; - 76048F5B3375D5784C0B5324D1BE08D7 /* MBLGyroBMI160Format.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGyroBMI160Format.h; path = MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160Format.h; sourceTree = ""; }; - 7622CCBF862B6B768ED7FBD7F3DA490F /* MBLSPIData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLSPIData+Private.h"; path = "MetaWear/Internal/Modules/Serial/MBLSPIData+Private.h"; sourceTree = ""; }; - 76BDD73914207FAFFF3E9CF5C71B1250 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMagnetometerBMM150PeriodicMagneticFieldEvent.m; path = MetaWear/Internal/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150PeriodicMagneticFieldEvent.m; sourceTree = ""; }; - 76E454A82BFF17A592A4B90B73930D61 /* MBLMockUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMockUtils.m; path = MetaWear/Internal/Mocks/MBLMockUtils.m; sourceTree = ""; }; - 7784E31355FEBC6941C37143FAD1BB78 /* MBLDataSample+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLDataSample+Private.h"; path = "MetaWear/Internal/Core/MBLDataSample+Private.h"; sourceTree = ""; }; - 78BE644057CFCCF385C1B31DD709F1C6 /* MBLMagnetometerData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMagnetometerData.m; path = MetaWear/Classes/Modules/Magnetometer/MBLMagnetometerData.m; sourceTree = ""; }; - 79009A415E1CA0B87F12D4F51E03E275 /* MBLHapticBuzzer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLHapticBuzzer.m; path = MetaWear/Classes/Modules/HapticBuzzer/MBLHapticBuzzer.m; sourceTree = ""; }; - 7965DF8D05996851B19C61D851F9D1D0 /* MBLI2CData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLI2CData.h; path = MetaWear/Classes/Modules/Serial/MBLI2CData.h; sourceTree = ""; }; - 798B5C3BB9132B9FDB5D673145BEC855 /* MBLStringData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLStringData+Private.h"; path = "MetaWear/Internal/Core/MBLStringData+Private.h"; sourceTree = ""; }; - 799D9302D1CE2454BF686DF875D0320A /* MBProgressHUD.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = MBProgressHUD.h; sourceTree = ""; }; - 79C8049DB69892D6593AFA7630E7932F /* StaticDataTableViewController.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = StaticDataTableViewController.debug.xcconfig; sourceTree = ""; }; - 79DAF916659E8B5554A2381CE21AEABA /* MBLFilter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLFilter.m; path = MetaWear/Classes/Core/MBLFilter.m; sourceTree = ""; }; - 79E7C3C9FA6588559703C398E7688432 /* MBLConductanceData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLConductanceData.m; path = MetaWear/Internal/Modules/Conductance/MBLConductanceData.m; sourceTree = ""; }; + 748E831377F55E2DEFF12C9EAD1EDA36 /* ColorPaletteControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPaletteControl.swift; path = FlexColorPicker/Classes/Controls/ColorPaletteControl.swift; sourceTree = ""; }; + 756D781D44346D6C9C684FFC30C24D2B /* Task+WhenAny.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Task+WhenAny.swift"; path = "Sources/BoltsSwift/Task+WhenAny.swift"; sourceTree = ""; }; + 767F239AADD5DE5511FC5DB522D50055 /* CustomColorPickerViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomColorPickerViewController.swift; path = FlexColorPicker/Classes/CustomColorPickerViewController.swift; sourceTree = ""; }; 7AAC68B97AFA7C06A7C3CB3024300B34 /* Pods-MusicalCaneGame.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-MusicalCaneGame.release.xcconfig"; sourceTree = ""; }; - 7AEF8FF9DDA0EA639C8A63DF8F3EAD02 /* MBLAccelerometerShakeEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerShakeEvent.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerShakeEvent.m; sourceTree = ""; }; - 7AF74140BE838529FCBE559FF49324FE /* MBLMagnetometer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMagnetometer.h; path = MetaWear/Classes/Modules/Magnetometer/MBLMagnetometer.h; sourceTree = ""; }; - 7B005DFE326C47396B8658C6BC3E3088 /* BFTask+MBLExtensions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "BFTask+MBLExtensions.m"; path = "MetaWear/Classes/Categories/BFTask+MBLExtensions.m"; sourceTree = ""; }; - 7B842C1CF9D05CBEB663920D19E57722 /* MBLMovingAverage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMovingAverage.m; path = MetaWear/Internal/Core/MBLMovingAverage.m; sourceTree = ""; }; - 7C8301370646F1F03A57FE5982C6618B /* MBLOrientationData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLOrientationData.h; path = MetaWear/Classes/Modules/Accelerometer/MBLOrientationData.h; sourceTree = ""; }; - 7C98A12DCBC5C73CA0813B0F0BB29E4C /* MBLAccelerometerMMA8452QOrientationFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerMMA8452QOrientationFormat.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452QOrientationFormat.h; sourceTree = ""; }; - 7CC753C6CEF0996735AB8C22A51FDF76 /* Bolts.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Bolts.modulemap; sourceTree = ""; }; - 7CDA43646778C7DF1FF0FA8624D6F105 /* FastCoding.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FastCoding.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7CFBCFD2BF9FC802D2DF954EBFF6CBAF /* MBLBarometer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBarometer.h; path = MetaWear/Classes/Modules/Barometer/MBLBarometer.h; sourceTree = ""; }; - 7EE225CB21810DD025D78280C1B2474F /* MBLFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLFormat.h; path = MetaWear/Internal/Core/MBLFormat.h; sourceTree = ""; }; - 7FE83A6332BFB6ACF4D7F6098D332826 /* MBLNeopixel+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLNeopixel+Private.h"; path = "MetaWear/Internal/Modules/Neopixel/MBLNeopixel+Private.h"; sourceTree = ""; }; - 800CCDF7A423E20D6E58606E2618A753 /* MBLRMSAccelerometerData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLRMSAccelerometerData.h; path = MetaWear/Classes/Modules/Accelerometer/MBLRMSAccelerometerData.h; sourceTree = ""; }; - 80177AF5756ECF16947D8BC3FB15DA32 /* MBLEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLEvent.m; path = MetaWear/Classes/Core/MBLEvent.m; sourceTree = ""; }; - 8060AB9A8C984249C5C707878D88D5EC /* MBLHapticBuzzer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLHapticBuzzer.h; path = MetaWear/Classes/Modules/HapticBuzzer/MBLHapticBuzzer.h; sourceTree = ""; }; - 80C1FEEFB923E9AAEF622948ABBBCB82 /* ComponentSliderDelegates.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ComponentSliderDelegates.swift; path = FlexColorPicker/Classes/ControlDelegates/ComponentSliderDelegates.swift; sourceTree = ""; }; - 80EF906667CF40840440B6176DB8E974 /* MBLLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLLogger.m; path = MetaWear/Internal/Core/MBLLogger.m; sourceTree = ""; }; - 80F929B0B2C6125D7E424E4A8D45F92F /* BFCancellationTokenRegistration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFCancellationTokenRegistration.h; path = Bolts/Common/BFCancellationTokenRegistration.h; sourceTree = ""; }; - 81186E6794F9E16E132D1042A3A7382D /* MBLBluetoothPeripheralMock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBluetoothPeripheralMock.m; path = MetaWear/Internal/Mocks/MBLBluetoothPeripheralMock.m; sourceTree = ""; }; - 81E83D2644E55250C1FBDC664E9792F8 /* FTS5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FTS5.swift; path = Sources/SQLite/Extensions/FTS5.swift; sourceTree = ""; }; - 8201272484180FA4D05CA43D01CE4B97 /* MBLLoggingV2.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLLoggingV2.m; path = MetaWear/Internal/Modules/Logging/MBLLoggingV2.m; sourceTree = ""; }; - 820C5930C99368E34D4BA3FF59AB6DC8 /* MBLMetaWear+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLMetaWear+Private.h"; path = "MetaWear/Internal/Core/MBLMetaWear+Private.h"; sourceTree = ""; }; - 821A25C88C6989010CF8A849993C7D4E /* MBLTriggeredRead.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLTriggeredRead.m; path = MetaWear/Internal/Core/MBLTriggeredRead.m; sourceTree = ""; }; - 832E6B3B6A39524018A87DF2CB10161D /* MBLLED+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLLED+Private.h"; path = "MetaWear/Internal/Modules/LED/MBLLED+Private.h"; sourceTree = ""; }; - 837BDA0EFF5B420C1734354EE59F809C /* MBLLED.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLLED.h; path = MetaWear/Classes/Modules/LED/MBLLED.h; sourceTree = ""; }; - 839C1FE41EFED619CF628B14E7A166FA /* MBLGPIOPin.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGPIOPin.h; path = MetaWear/Classes/Modules/GPIO/MBLGPIOPin.h; sourceTree = ""; }; - 83E4339E9413CB51E88384FD2BB24A82 /* MBLAccelerometerBoschLowOrHighGEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschLowOrHighGEvent.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschLowOrHighGEvent.h; sourceTree = ""; }; - 8491C15C76BF353764E258E377D0C2E8 /* MBLCorrectedFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLCorrectedFormat.h; path = MetaWear/Internal/Modules/SensorFusion/MBLCorrectedFormat.h; sourceTree = ""; }; - 8499C6937A05616246FD6735CF490211 /* MBLAccelerometerMMA8452QOrientationFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerMMA8452QOrientationFormat.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452QOrientationFormat.m; sourceTree = ""; }; - 84ED3110C21AB37CCDDF68B23BA0B774 /* PRTween-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "PRTween-dummy.m"; sourceTree = ""; }; - 857526C5F59A06EEAFB4093855DCF331 /* MBLAccelerometerBMI160StepEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBMI160StepEvent.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMI160/MBLAccelerometerBMI160StepEvent.h; sourceTree = ""; }; - 862315B9E7FA3F370EF8449599E625A0 /* PRTween.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PRTween.m; path = lib/PRTween.m; sourceTree = ""; }; - 8626A34A32F4E09F7180102BDA29423B /* MBLDispatchQueue.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLDispatchQueue.h; path = MetaWear/Internal/Core/MBLDispatchQueue.h; sourceTree = ""; }; + 7B381E4993D646F1889B08E2056F6B10 /* RadialHSBPaletteDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadialHSBPaletteDelegate.swift; path = FlexColorPicker/Classes/ControlDelegates/RadialHSBPaletteDelegate.swift; sourceTree = ""; }; + 7B4B70F59939EEA547A42705D781E63C /* CGRectExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CGRectExtension.swift; path = FlexColorPicker/Classes/Utilities/CGRectExtension.swift; sourceTree = ""; }; + 7DF415FCE4EC0E6B83191E69BD55A61F /* MetaWear.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MetaWear.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7E51668FB3B651E6FE54DCD75388792D /* MetaWearData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MetaWearData.swift; path = MetaWear/Core/MetaWearData.swift; sourceTree = ""; }; + 7E837DDBD7E6B0A0B51BCC223AB74E2F /* LogDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LogDelegate.swift; path = MetaWear/Core/LogDelegate.swift; sourceTree = ""; }; + 7F27C589134A2FEE1DBD415460594611 /* MBProgressHUD.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MBProgressHUD.debug.xcconfig; sourceTree = ""; }; + 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 80A006ECE0C1D98020B9C6469CBAEF3A /* PRTween-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PRTween-umbrella.h"; sourceTree = ""; }; + 810843420244FD34B1DCCEF5EC203EEE /* FlexColorPicker-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FlexColorPicker-dummy.m"; sourceTree = ""; }; + 81B6F2535F4EE9FA4A2315176F72688B /* Blob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Blob.swift; path = Sources/SQLite/Core/Blob.swift; sourceTree = ""; }; + 848304F115E7770A6DA90BE2C0D9804B /* PRTween-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PRTween-prefix.pch"; sourceTree = ""; }; + 84BD1D885F3A9889ED88A68F6C0F90CB /* Query.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Query.swift; path = Sources/SQLite/Typed/Query.swift; sourceTree = ""; }; + 851BADBA8A6FFFB5EC69F243391C54B4 /* DateAndTimeFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DateAndTimeFunctions.swift; path = Sources/SQLite/Typed/DateAndTimeFunctions.swift; sourceTree = ""; }; + 856008788ABB599F1BEA9ECE9C974858 /* Bolts-Swift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Bolts-Swift-umbrella.h"; sourceTree = ""; }; 86ECAEF7F5628942327EAC2B0CD54470 /* Pods-MusicalCaneGame-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-MusicalCaneGame-Info.plist"; sourceTree = ""; }; - 8738C2009B7045C579D0696C83A180A4 /* MBLOnDieTemperature0.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLOnDieTemperature0.h; path = MetaWear/Internal/Modules/Temperature/MBLOnDieTemperature0.h; sourceTree = ""; }; - 8748CB4814020756E8C95D76D95C374A /* DateAndTimeFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DateAndTimeFunctions.swift; path = Sources/SQLite/Typed/DateAndTimeFunctions.swift; sourceTree = ""; }; - 879B08BDF7758C925448C0BFEE3B29EB /* FlexColorPicker.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FlexColorPicker.debug.xcconfig; sourceTree = ""; }; - 87E0C59754C9E2B1A128BA2D4C6A24D4 /* MBLSettings.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLSettings.m; path = MetaWear/Classes/Modules/Settings/MBLSettings.m; sourceTree = ""; }; - 88A78BC9BED1903F288B99F8243780E3 /* MBLGyroData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLGyroData+Private.h"; path = "MetaWear/Internal/Modules/Gyro/MBLGyroData+Private.h"; sourceTree = ""; }; - 8962D19DDF25CA96D9564E5DF5B80EE2 /* PRTween.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = PRTween.modulemap; sourceTree = ""; }; - 8970EEE842F7C944B400E85182FA4D7E /* MBLI2C.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLI2C.m; path = MetaWear/Classes/Modules/I2C/MBLI2C.m; sourceTree = ""; }; - 897B8CDE723F546E2116F984DF33DF5C /* MBLFirmwareUpdateManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLFirmwareUpdateManager.m; path = MetaWear/Internal/DFU/MBLFirmwareUpdateManager.m; sourceTree = ""; }; - 89E9AD6A613937C723DAE21265CF0A32 /* MBLMacro.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMacro.h; path = MetaWear/Internal/Modules/Macro/MBLMacro.h; sourceTree = ""; }; - 8AA5616E4E4280DA16737BF116DD49F6 /* MBLAnonymousEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAnonymousEvent.m; path = MetaWear/Classes/Core/MBLAnonymousEvent.m; sourceTree = ""; }; - 8AFF5162AB9978EB3C44DC08A7021F3F /* MBLModuleInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLModuleInfo.m; path = MetaWear/Internal/Core/MBLModuleInfo.m; sourceTree = ""; }; - 8B3A9FC030CAA3A37E8B12FB7E4DDA76 /* MBLAccelerometerBoschFlatFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschFlatFormat.h; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFlatFormat.h; sourceTree = ""; }; - 8B61285A50EC5FE9ABE7406F805BD7ED /* MBLFilter+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLFilter+Private.h"; path = "MetaWear/Internal/Core/MBLFilter+Private.h"; sourceTree = ""; }; + 88AB8185F159FC1D39C785EE66D4F58A /* Helpers.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Helpers.swift; path = Sources/SQLite/Helpers.swift; sourceTree = ""; }; + 88EF07E07BC8B02D7922894DD2D4FD83 /* haptic.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = haptic.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/peripheral/cpp/haptic.cpp"; sourceTree = ""; }; + 89590357DAA3D6FE1273B2AA18B10370 /* miniz.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = miniz.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/dfu/cpp/miniz.cpp"; sourceTree = ""; }; + 8AFC83344D6B8191AE1C143E1E02E283 /* ColorControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorControl.swift; path = FlexColorPicker/Classes/Controls/ColorControl.swift; sourceTree = ""; }; 8B8FAB0D627B17EDE1366984278705D9 /* MBProgressHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MBProgressHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8BAE0694187091665D4BF2CC5C546B7C /* LimitedGestureViewDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LimitedGestureViewDelegate.swift; path = FlexColorPicker/Classes/Utilities/LimitedGestureViewDelegate.swift; sourceTree = ""; }; - 8BC8D097C45C807B6B0F9759CE423128 /* RectangularHSBPaletteDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RectangularHSBPaletteDelegate.swift; path = FlexColorPicker/Classes/ControlDelegates/RectangularHSBPaletteDelegate.swift; sourceTree = ""; }; - 8C1E3DBB7FF2A60BFDBFDCED8736F8C7 /* MBLNumericData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLNumericData.h; path = MetaWear/Classes/Core/MBLNumericData.h; sourceTree = ""; }; - 8C228A5E96ACBA64A79B79955A47D11D /* MBLPhotometer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLPhotometer.h; path = MetaWear/Classes/Modules/Photometer/MBLPhotometer.h; sourceTree = ""; }; - 8C3FDF931FB3F22106AEB74ADE3EE6B0 /* MBLAccelerometerBoschFlatEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschFlatEvent.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFlatEvent.m; sourceTree = ""; }; - 8C8165089578A149C045394501D28749 /* MBLMagnetometer+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLMagnetometer+Private.h"; path = "MetaWear/Internal/Modules/Magnetometer/MBLMagnetometer+Private.h"; sourceTree = ""; }; - 8CE957C206AFAC66F176C3FF5B9495C7 /* AbstractColorControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AbstractColorControl.swift; path = FlexColorPicker/Classes/Controls/AbstractColorControl.swift; sourceTree = ""; }; - 8D812B690E5B0D2F8F5F6CAE1E33FB56 /* MBLAccelerometerBMI160MotionEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBMI160MotionEvent.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMI160/MBLAccelerometerBMI160MotionEvent.m; sourceTree = ""; }; - 8E6A9A89A7A6D2068DA309A57810A3F3 /* MBLAccelerometerBosch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBosch.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBosch.h; sourceTree = ""; }; - 8E9EBD3665678A28C911C3EC04616F63 /* SQLite-Bridging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "SQLite-Bridging.m"; path = "Sources/SQLiteObjc/SQLite-Bridging.m"; sourceTree = ""; }; - 8EFA8BB36D6A79D6122BAADD7F82D3DC /* GradientView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = FlexColorPicker/Classes/Views/GradientView.swift; sourceTree = ""; }; + 8CD32BC358ADAD2D2224880C6512FE29 /* logging.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/logging.cpp"; sourceTree = ""; }; + 8CE762A6D7D985FF99D6392847EC42E8 /* ColorControlContentView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorControlContentView.swift; path = FlexColorPicker/Classes/Views/ColorControlContentView.swift; sourceTree = ""; }; + 8E2005539348BC2EC04A37B194E1D027 /* gpio.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = gpio.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/gpio.cpp"; sourceTree = ""; }; + 8ED97638BEF69DFDE5546F33EDDAFA5C /* TaskCompletionSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TaskCompletionSource.swift; path = Sources/BoltsSwift/TaskCompletionSource.swift; sourceTree = ""; }; + 8F89C30C49386D56C5D3FF459FA8B560 /* multichanneltemperature.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = multichanneltemperature.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/multichanneltemperature.cpp"; sourceTree = ""; }; 8FDEEE460A0914B34721D75B691BA3A1 /* Pods-MusicalCaneGame-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-MusicalCaneGame-frameworks.sh"; sourceTree = ""; }; - 8FED6CFDFA4AED3BC7EDB54252A9B78C /* MBLAccelerometerBoschTapEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschTapEvent.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschTapEvent.h; sourceTree = ""; }; - 906779D31DDEA2E5A800163C9367D00E /* StaticDataTableViewController-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "StaticDataTableViewController-prefix.pch"; sourceTree = ""; }; - 917209A52726E7382B909C115B2A81F6 /* Bolts.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Bolts.h; path = Bolts/Common/Bolts.h; sourceTree = ""; }; - 92D515E4EBB8012585D33EBE80ABDE75 /* MBLAccelerometerAxisReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerAxisReadyEvent.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerAxisReadyEvent.h; sourceTree = ""; }; - 93473D232BB71FEE0EB8DC34DCE6C8B4 /* MBProgressHUD-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MBProgressHUD-prefix.pch"; sourceTree = ""; }; - 9412CC7AD155C9478A8CAAC3A112EDDD /* MetaWearPrivate-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "MetaWearPrivate-dummy.m"; sourceTree = ""; }; - 94F8B62730BE54CC80EFCB063CE8DB0A /* MBLGyroBMI160+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLGyroBMI160+Private.h"; path = "MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160+Private.h"; sourceTree = ""; }; - 95E4D7D504BD6D0C20D213018DE0D8C9 /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.h; path = MetaWear/Internal/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.h; sourceTree = ""; }; - 95F84F11F10A37945DEACE2F521BAF09 /* MBLAccelerometerBoschFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschFormat.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFormat.m; sourceTree = ""; }; - 9719CDA5A212D1B94FE445E855713AE3 /* MBLDeviceLookup.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLDeviceLookup.m; path = MetaWear/Internal/Mocks/MBLDeviceLookup.m; sourceTree = ""; }; - 97A9BB5093D62A978475C22DC60FBAAC /* MBLPhotometerTCS3472.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLPhotometerTCS3472.m; path = MetaWear/Classes/Modules/Photometer/PhotometerTCS3472/MBLPhotometerTCS3472.m; sourceTree = ""; }; - 97DE674DA17D28837EEE190D55B1C72C /* MBLAccelerometerData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerData.h; path = MetaWear/Classes/Modules/Accelerometer/MBLAccelerometerData.h; sourceTree = ""; }; - 997426A3EEBF7C2EB7DE297CA7BC5413 /* MBLRGBData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLRGBData.h; path = MetaWear/Classes/Modules/Photometer/MBLRGBData.h; sourceTree = ""; }; - 99962F735427ACDF3EC96AB3A35302A3 /* MBLBluetoothPeripheralMock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBluetoothPeripheralMock.h; path = MetaWear/Internal/Mocks/MBLBluetoothPeripheralMock.h; sourceTree = ""; }; - 9A83AECEA017C91C9F5CBA32F375B09E /* MBLBluetoothCentralMock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBluetoothCentralMock.h; path = MetaWear/Internal/Mocks/MBLBluetoothCentralMock.h; sourceTree = ""; }; - 9AEF92ED6E230F7C4BE4000DC9B2F37F /* MBLConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLConstants.h; path = MetaWear/Classes/Core/MBLConstants.h; sourceTree = ""; }; - 9C073299F231C20AA958CCE9BE21E29B /* MBLConductance.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLConductance.m; path = MetaWear/Classes/Modules/Conductance/MBLConductance.m; sourceTree = ""; }; - 9C42D16CF91748AA1CCEA014D3D93140 /* MBLBarometerBoschPeriodicAltitudeEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLBarometerBoschPeriodicAltitudeEvent.m; path = MetaWear/Internal/Modules/Barometer/BarometerBosch/MBLBarometerBoschPeriodicAltitudeEvent.m; sourceTree = ""; }; - 9C5799488BC7801B1D24372B47401F65 /* MBLExternalThermistor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLExternalThermistor.m; path = MetaWear/Classes/Modules/Temperature/MBLExternalThermistor.m; sourceTree = ""; }; - 9D900690513FC59CD201C4FEC888AB9B /* MBLAnonymousEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAnonymousEvent+Private.h"; path = "MetaWear/Internal/Core/MBLAnonymousEvent+Private.h"; sourceTree = ""; }; + 9166DFD798F4A1606D7677551E3BD4EC /* Collation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Collation.swift; path = Sources/SQLite/Typed/Collation.swift; sourceTree = ""; }; + 922596DF6C398433B0444D3BB469CE7C /* DefaultColorPickerViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultColorPickerViewController.swift; path = FlexColorPicker/Classes/DefaultColorPickerViewController.swift; sourceTree = ""; }; + 93819BB5AB4610BFDF6F0FC2282E4DDE /* MBProgressHUD.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = MBProgressHUD.m; sourceTree = ""; }; + 97BE74803775549BE6BF46F72308B6C9 /* UIColorExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIColorExtension.swift; path = FlexColorPicker/Classes/Utilities/UIColorExtension.swift; sourceTree = ""; }; + 9857283877591447B1363F9BD57800B5 /* StaticDataTableViewController.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = StaticDataTableViewController.modulemap; sourceTree = ""; }; + 99752ACF6F055D42962C66A5DE6DF958 /* StaticDataTableViewController-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "StaticDataTableViewController-Info.plist"; sourceTree = ""; }; + 99BD5F29CB67E3572EB2165C71C69402 /* MetaWear.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MetaWear.swift; path = MetaWear/Core/MetaWear.swift; sourceTree = ""; }; + 9AB3434E3EC03D58E5256B36E21F667E /* metawearboard.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = metawearboard.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/impl/cpp/metawearboard.cpp"; sourceTree = ""; }; + 9B1BDA10EB511E35ECD6ED7664C4CEEE /* SQLite.swift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SQLite.swift.modulemap; sourceTree = ""; }; + 9BB8A576C5797EB68CB23964A394D94C /* magnetometer_bmm150.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = magnetometer_bmm150.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/magnetometer_bmm150.cpp"; sourceTree = ""; }; 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 9DC7BF0532FFB6F12EAF271B32F7DF12 /* MBLRegister.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLRegister.h; path = MetaWear/Classes/Core/MBLRegister.h; sourceTree = ""; }; - 9DEE8A761E6F3EFD39AC435300060A92 /* ColorSliderControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorSliderControl.swift; path = FlexColorPicker/Classes/Controls/ColorSliderControl.swift; sourceTree = ""; }; - 9E05B40C0330E22A967C1E33D89416D5 /* SQLite.swift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SQLite.swift.release.xcconfig; sourceTree = ""; }; - 9E2EB1A561C2951A3F29D98C21C6D68F /* MBLOrientationData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLOrientationData+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/MBLOrientationData+Private.h"; sourceTree = ""; }; - 9E6328E370911FF7407A878B58FBE742 /* MBLModuleMock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLModuleMock.m; path = MetaWear/Internal/Mocks/MBLModuleMock.m; sourceTree = ""; }; - 9F3FB7312B0FB66FA2194029BF866463 /* FastCoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FastCoder.m; path = FastCoder/FastCoder.m; sourceTree = ""; }; - A0BEA4B8CB2275B94D4A678EEA3F9726 /* MBLSPIData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLSPIData.m; path = MetaWear/Classes/Modules/Serial/MBLSPIData.m; sourceTree = ""; }; - A0C072E7EBB31D497A02922D12FFD0BF /* BFCancellationTokenRegistration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationTokenRegistration.m; path = Bolts/Common/BFCancellationTokenRegistration.m; sourceTree = ""; }; - A1B3444495ED8736F3DFC544DA9D9F22 /* MBLTemperature.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLTemperature.h; path = MetaWear/Classes/Modules/Temperature/MBLTemperature.h; sourceTree = ""; }; - A31D7E886BA2EE4D7FE6732E7F0F8C08 /* BFCancellationToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationToken.m; path = Bolts/Common/BFCancellationToken.m; sourceTree = ""; }; - A3D03AEC363BD828752113CECC7C80C6 /* MBLEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLEvent.h; path = MetaWear/Classes/Core/MBLEvent.h; sourceTree = ""; }; - A40DCE98EAF323F2D77DBC24BEA5D411 /* MBLAccelerometerFreeFallEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerFreeFallEvent.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerFreeFallEvent.h; sourceTree = ""; }; - A4308FFBA546624C19F8BA0E4F1211BB /* FlexColorPicker-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FlexColorPicker-prefix.pch"; sourceTree = ""; }; - A4397048407923C022BF6296206C83C2 /* MBLANCSEventData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLANCSEventData.h; path = MetaWear/Classes/Modules/ANCS/MBLANCSEventData.h; sourceTree = ""; }; - A50E162915108843410E01B430AFCF82 /* MBLRMSAccelerometerData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLRMSAccelerometerData+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/MBLRMSAccelerometerData+Private.h"; sourceTree = ""; }; - A5DBB6C06E3DAB5CC269D3472516F20C /* MBLFirmwareBuild.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLFirmwareBuild.m; path = MetaWear/Internal/Core/MBLFirmwareBuild.m; sourceTree = ""; }; - A6080F0AAC1DB95455EDE9EF02DBBAF7 /* BFCancellationTokenSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFCancellationTokenSource.m; path = Bolts/Common/BFCancellationTokenSource.m; sourceTree = ""; }; - A6D37657F3EE943952978BAB8DA03E58 /* MBLAnonymousEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAnonymousEvent.h; path = MetaWear/Classes/Core/MBLAnonymousEvent.h; sourceTree = ""; }; - A74539E4276BAD6B5B7AD628754C5504 /* MBLProximity.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLProximity.h; path = MetaWear/Classes/Modules/Proximity/MBLProximity.h; sourceTree = ""; }; - A75EEDEF0F8BD9F3DB6E1D7268D8C0E3 /* BFTask.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFTask.m; path = Bolts/Common/BFTask.m; sourceTree = ""; }; - A97E33CBC9D1460FA0817700D3D58EFC /* MBLFirmwareBuild.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLFirmwareBuild.h; path = MetaWear/Internal/Core/MBLFirmwareBuild.h; sourceTree = ""; }; - A9D7C3BE275BD60DCC89C7FD4F387EFF /* UIColorExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIColorExtension.swift; path = FlexColorPicker/Classes/Utilities/UIColorExtension.swift; sourceTree = ""; }; - AA41C9AFBA1DEDF1DB28131ED13B1416 /* MBLTemperatureV1.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLTemperatureV1.h; path = MetaWear/Internal/Modules/Temperature/MBLTemperatureV1.h; sourceTree = ""; }; - AB7BB654211C9E0BD7A936321B39F4ED /* MBLHygrometerBME280PeriodicHumidityEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLHygrometerBME280PeriodicHumidityEvent.m; path = MetaWear/Internal/Modules/Hygrometer/HygrometerBME280/MBLHygrometerBME280PeriodicHumidityEvent.m; sourceTree = ""; }; - AB8E8A0E6C5761A0D832978E831F8B7E /* MBLLoggingV2.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLLoggingV2.h; path = MetaWear/Internal/Modules/Logging/MBLLoggingV2.h; sourceTree = ""; }; - ABF926A861C75B028D5DEEAA25BBED22 /* MBLHygrometer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLHygrometer.h; path = MetaWear/Classes/Modules/Hygrometer/MBLHygrometer.h; sourceTree = ""; }; - AC09702064EE3145D24A7F67CEC32E08 /* MBLAccelerometerBoschDataReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschDataReadyEvent.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschDataReadyEvent.m; sourceTree = ""; }; - AD032BAD9297C34CC59A56B6F37632D8 /* StaticDataTableViewController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = StaticDataTableViewController.m; sourceTree = ""; }; - AD10C0FA17E34B86E7160A70689FBC3C /* MBLSettings+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLSettings+Private.h"; path = "MetaWear/Internal/Modules/Settings/MBLSettings+Private.h"; sourceTree = ""; }; - ADB19BA4C93D3926CE12B4649B33E5FE /* MBLGyroBMI160AxisReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGyroBMI160AxisReadyEvent.m; path = MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160AxisReadyEvent.m; sourceTree = ""; }; - ADE85F46048EC1F3C36566473CA0DD97 /* MBLDataSample.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLDataSample.h; path = MetaWear/Classes/Core/MBLDataSample.h; sourceTree = ""; }; - AEE6B2B57E2658D16BB004197E73ADB7 /* MBLAccelerometerMMA8452Q.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerMMA8452Q.h; path = MetaWear/Classes/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452Q.h; sourceTree = ""; }; - AFA6D3F966A7D6C6CC905F69C04ED4DF /* MBLLED.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLLED.m; path = MetaWear/Classes/Modules/LED/MBLLED.m; sourceTree = ""; }; - AFB4497D5CD9672F5C95C767490B8BE1 /* MBLMagnetometerBMM150+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLMagnetometerBMM150+Private.h"; path = "MetaWear/Internal/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150+Private.h"; sourceTree = ""; }; - B125C22BB5BB7A4B5211815B2C948FF4 /* FastCoding-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FastCoding-umbrella.h"; sourceTree = ""; }; - B134A1DB88245EF935E2BC1D6B053A2B /* MBLAccelerometerPackedDataReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerPackedDataReadyEvent.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerPackedDataReadyEvent.m; sourceTree = ""; }; - B1CD72E1EDED538FB7F734E6A318EEF1 /* MBLGravityFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGravityFormat.h; path = MetaWear/Internal/Modules/SensorFusion/MBLGravityFormat.h; sourceTree = ""; }; - B1F094F5014C64256F003CA4D7015EEB /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; - B279E17CC4C99B56C4AB6FA7871B3A09 /* MBLAccelerometerBoschFlatEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBoschFlatEvent.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFlatEvent.h; sourceTree = ""; }; - B2AF51A650223D1BB2740F2372BE7090 /* Blob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Blob.swift; path = Sources/SQLite/Core/Blob.swift; sourceTree = ""; }; - B33CDBDF1B9436C886A3943A9CFBF3A7 /* UIViewExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIViewExtension.swift; path = FlexColorPicker/Classes/Utilities/UIViewExtension.swift; sourceTree = ""; }; - B42FA1179121C2BACE59FD1E5CCD9D15 /* MBLAmbientLight+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAmbientLight+Private.h"; path = "MetaWear/Internal/Modules/AmbientLight/MBLAmbientLight+Private.h"; sourceTree = ""; }; - B4D3F620186E034F7C623B428D3109BD /* ColorPickerThumbView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPickerThumbView.swift; path = FlexColorPicker/Classes/Views/ColorPickerThumbView.swift; sourceTree = ""; }; + 9E5CB155C33429C2CEA4B8DBAE6B5C05 /* FlexColorPicker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FlexColorPicker.h; path = FlexColorPicker/Classes/FlexColorPicker.h; sourceTree = ""; }; + 9F959FABCF6DA4F1D78ED752EDBFA470 /* PRTween.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = PRTween.modulemap; sourceTree = ""; }; + A0883C90F4487E6DD44FF9DAE921E35B /* SQLite.swift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SQLite.swift-dummy.m"; sourceTree = ""; }; + A31050EA589DAF8798D4F5FD0C699B2A /* async_creator.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = async_creator.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/platform/cpp/async_creator.cpp"; sourceTree = ""; }; + A47FEBBA1EE6AED3B97F30327C09C8E3 /* FTS5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FTS5.swift; path = Sources/SQLite/Extensions/FTS5.swift; sourceTree = ""; }; + A69C3F124C8003BE9DD9E0B347B4B24C /* PaletteAwareScrollView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PaletteAwareScrollView.swift; path = FlexColorPicker/Classes/Views/PaletteAwareScrollView.swift; sourceTree = ""; }; + A735833176106989D12FB071A9461289 /* Value.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Value.swift; path = Sources/SQLite/Core/Value.swift; sourceTree = ""; }; + A8F2C63252A09E44D38172A5608073A1 /* PRTweenTimingFunctions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PRTweenTimingFunctions.h; path = lib/PRTweenTimingFunctions.h; sourceTree = ""; }; + AC214CCB2D7EC6565F37289452B522FE /* PRTween-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "PRTween-dummy.m"; sourceTree = ""; }; + AC852EC78B5163CEFEF2E069E7BA4BE1 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; + ACF5B3235A355BACAD2D100F5491E44A /* ambientlight_ltr329.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = ambientlight_ltr329.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/ambientlight_ltr329.cpp"; sourceTree = ""; }; + AEAB9015993CEBB553A0414679F7395D /* RTree.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RTree.swift; path = Sources/SQLite/Extensions/RTree.swift; sourceTree = ""; }; + B31634A27AC13E9EEE2F0989C18B1870 /* PRTween.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = PRTween.h; path = lib/PRTween.h; sourceTree = ""; }; + B3A2F747328473C2A352F6941CF34BD8 /* FlexColorPicker-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FlexColorPicker-umbrella.h"; sourceTree = ""; }; + B4DE3FB54847A63C86EC53E8DC8530D9 /* MetaWear.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MetaWear.debug.xcconfig; sourceTree = ""; }; B5675162CF07A333A600854AC822CAF5 /* Pods-MusicalCaneGame.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-MusicalCaneGame.debug.xcconfig"; sourceTree = ""; }; - B60A4C304F52AA1358CD318BF8438FF7 /* MBLAccelerometerDataReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerDataReadyEvent.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerDataReadyEvent.m; sourceTree = ""; }; - B60C6D4316257A8592A9C8FFD2E4C1D2 /* MBLAccelerometerMMA8452QRMSFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerMMA8452QRMSFormat.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452QRMSFormat.m; sourceTree = ""; }; - B634A03BAB223550C28DA4D4C43BCE38 /* BFExecutor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFExecutor.h; path = Bolts/Common/BFExecutor.h; sourceTree = ""; }; - B66025F0A7A7B300D691863FA50F11D7 /* MBLLogging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLLogging.m; path = MetaWear/Internal/Modules/Logging/MBLLogging.m; sourceTree = ""; }; + B626047F766959C564A58087ACA58F97 /* fts3_tokenizer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = fts3_tokenizer.h; path = Sources/SQLiteObjc/fts3_tokenizer.h; sourceTree = ""; }; B6B2138B534DA2D64E869EF442A8C7D1 /* Pods_MusicalCaneGame.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MusicalCaneGame.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - B6E391DFCD4A71DF7EA3A6D8477D386B /* MBLAccelerometerBosch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBosch.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBosch.m; sourceTree = ""; }; - B6E6F6428599AAF50B572B1FD082CE70 /* MBLMagnetometerBMM150Format.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMagnetometerBMM150Format.h; path = MetaWear/Internal/Modules/Magnetometer/MagnetometerBMM150/MBLMagnetometerBMM150Format.h; sourceTree = ""; }; - B77B4FF4C17BA842D92B6BC68F66DCCD /* PaletteControls.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PaletteControls.swift; path = FlexColorPicker/Classes/Controls/PaletteControls.swift; sourceTree = ""; }; - B79044677BC189DBE3E11CA1A5D45456 /* MBLEulerAngleData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLEulerAngleData+Private.h"; path = "MetaWear/Internal/Modules/SensorFusion/MBLEulerAngleData+Private.h"; sourceTree = ""; }; - BB91C79095FC4962E764219F9A601235 /* SQLite.swift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SQLite.swift-prefix.pch"; sourceTree = ""; }; - BC01372E68FAF8353E6B5FF3C839FE55 /* MBLDataSwitch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLDataSwitch.h; path = MetaWear/Classes/Core/MBLDataSwitch.h; sourceTree = ""; }; - BDCD67FA16C0A10BB731D87465C6E05F /* MBLMockPeripheralFactory.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMockPeripheralFactory.m; path = MetaWear/Internal/Mocks/MBLMockPeripheralFactory.m; sourceTree = ""; }; - BE11AF986689B3ACFB86F3F7A54B71B7 /* MBLEulerFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLEulerFormat.m; path = MetaWear/Internal/Modules/SensorFusion/MBLEulerFormat.m; sourceTree = ""; }; - BE3703D7CF94997EE0D61F4A95442741 /* MBLHygrometerBME280.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLHygrometerBME280.m; path = MetaWear/Classes/Modules/Hygrometer/HygrometerBME280/MBLHygrometerBME280.m; sourceTree = ""; }; - BE81BC86D60BB954223F36E9EBADEB9C /* MBLAccelerometerBMI160MotionEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBMI160MotionEvent+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMI160/MBLAccelerometerBMI160MotionEvent+Private.h"; sourceTree = ""; }; - BEC5AC5CB64ED4E1F0FFADAA163F3A2F /* MBLGyroBMI160.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGyroBMI160.m; path = MetaWear/Classes/Modules/Gyro/GyroBMI160/MBLGyroBMI160.m; sourceTree = ""; }; - BF08C236AA2798EE30C42E2EED2C4F1A /* MBLTimerEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLTimerEvent+Private.h"; path = "MetaWear/Internal/Modules/Timer/MBLTimerEvent+Private.h"; sourceTree = ""; }; - BF96EFA28DB351EBE7678639DBEEE959 /* MBLModule.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLModule.h; path = MetaWear/Classes/Core/MBLModule.h; sourceTree = ""; }; - BFBCEE9347037627B22BCB8770DBE213 /* MBLGPIO.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGPIO.m; path = MetaWear/Classes/Modules/GPIO/MBLGPIO.m; sourceTree = ""; }; - C034BDE0E58F942489EF132FFE65CF95 /* MBLAccelerometerBMI160.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBMI160.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMI160/MBLAccelerometerBMI160.h; sourceTree = ""; }; - C21E4B182C7E88A6C2637D759E596E90 /* MBLMetaWear.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMetaWear.m; path = MetaWear/Classes/Core/MBLMetaWear.m; sourceTree = ""; }; - C2E15C7CAF839B548FEC8915238371BE /* MBLAccelerometerBoschOrientationFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschOrientationFormat.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschOrientationFormat.m; sourceTree = ""; }; - C36B46123D96EED8AFC393D73A505F49 /* MBLDeviceLookup.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLDeviceLookup.h; path = MetaWear/Internal/Mocks/MBLDeviceLookup.h; sourceTree = ""; }; - C36BCB63685C8F467D7666E915B25FE1 /* MBLDeviceInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLDeviceInfo.m; path = MetaWear/Classes/Core/MBLDeviceInfo.m; sourceTree = ""; }; - C3A391E839582AAF0BFB4FE1830EE8BE /* MBLAccelerometerMMA8452QRMSFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerMMA8452QRMSFormat.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452QRMSFormat.h; sourceTree = ""; }; - C3DBA18C39DFD63A6E34ED9F78739553 /* MBLAnalytics.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAnalytics.m; path = MetaWear/Internal/Core/MBLAnalytics.m; sourceTree = ""; }; - C596C5CF2FA47DB70CEEBD0155610BCA /* ComponentSliderControls.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ComponentSliderControls.swift; path = FlexColorPicker/Classes/Controls/ComponentSliderControls.swift; sourceTree = ""; }; - C5ABAB1C2F3A3165F73F7E8EB46EDD41 /* Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/SQLite/Typed/Operators.swift; sourceTree = ""; }; - C65A26A196DDDE0F69C776EA4C8AD4CD /* ColorPaletteDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPaletteDelegate.swift; path = FlexColorPicker/Classes/ControlDelegates/ColorPaletteDelegate.swift; sourceTree = ""; }; - C74601C377948832E851B19266E34DC4 /* CustomColorPickerViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomColorPickerViewController.swift; path = FlexColorPicker/Classes/CustomColorPickerViewController.swift; sourceTree = ""; }; - C7516AC1991429F6A3B81EBCA1C708A3 /* MBLRegister+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLRegister+Private.h"; path = "MetaWear/Internal/Core/MBLRegister+Private.h"; sourceTree = ""; }; - C7CFF911E5E62F4576D5F62C22700FF5 /* PRTweenTimingFunctions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = PRTweenTimingFunctions.m; path = lib/PRTweenTimingFunctions.m; sourceTree = ""; }; - C7DC20CA8168B95E252E3D42883085AF /* FastCoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FastCoder.h; path = FastCoder/FastCoder.h; sourceTree = ""; }; - C831B453B2562186B3BDA684EA4ADFE6 /* FastCoding-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FastCoding-Info.plist"; sourceTree = ""; }; - C9316C8FB669D06A57EB51231B16FFE5 /* MBLFilter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLFilter.h; path = MetaWear/Classes/Core/MBLFilter.h; sourceTree = ""; }; - CA113996186396182E6481062F4AA736 /* RadialHSBPaletteDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadialHSBPaletteDelegate.swift; path = FlexColorPicker/Classes/ControlDelegates/RadialHSBPaletteDelegate.swift; sourceTree = ""; }; - CA5DE9F1D46C8C7DACC2C1C6A06C1C70 /* MBLHygrometerBME280.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLHygrometerBME280.h; path = MetaWear/Classes/Modules/Hygrometer/HygrometerBME280/MBLHygrometerBME280.h; sourceTree = ""; }; - CA70F8707E848340FC61F67D2D09DA6C /* MBLConstants+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLConstants+Private.h"; path = "MetaWear/Internal/Core/MBLConstants+Private.h"; sourceTree = ""; }; - CAA0C8F987AE0F0506C0177F097AAFF2 /* AggregateFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AggregateFunctions.swift; path = Sources/SQLite/Typed/AggregateFunctions.swift; sourceTree = ""; }; - CAF56CC7BF0723A62B749CD5DF597DB7 /* MBLProximityTSL2671.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLProximityTSL2671.h; path = MetaWear/Classes/Modules/Proximity/ProximityTSL2671/MBLProximityTSL2671.h; sourceTree = ""; }; - CC01879C87DED7F6F3014CC9690267C2 /* MBLQuaternionData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLQuaternionData+Private.h"; path = "MetaWear/Internal/Modules/SensorFusion/MBLQuaternionData+Private.h"; sourceTree = ""; }; - CCBB7805806FF294F5264BA8413A9B60 /* MBLTimerEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLTimerEvent.h; path = MetaWear/Classes/Modules/Timer/MBLTimerEvent.h; sourceTree = ""; }; - CCF4AAB7D3A5091626ADDD67F202425B /* MBLExternalThermistor0.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLExternalThermistor0.m; path = MetaWear/Internal/Modules/Temperature/MBLExternalThermistor0.m; sourceTree = ""; }; - CD20F39380856BCE4A46A32AB8DD3FED /* MBLData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLData.h; path = MetaWear/Classes/Core/MBLData.h; sourceTree = ""; }; - CD543DD9A37CED8E5D798EE760111A9D /* MBLBarometerBosch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBarometerBosch.h; path = MetaWear/Classes/Modules/Barometer/BarometerBosch/MBLBarometerBosch.h; sourceTree = ""; }; - CD5BAE72308C847F0DDDC961B9D1F1EB /* MBLBarometerBMP280.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBarometerBMP280.h; path = MetaWear/Classes/Modules/Barometer/BarometerBosch/BarometerBMP280/MBLBarometerBMP280.h; sourceTree = ""; }; - CE750EE45CE8CF012A77D168A395CC3A /* MBLBarometerBoschPeriodicAltitudeEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBarometerBoschPeriodicAltitudeEvent.h; path = MetaWear/Internal/Modules/Barometer/BarometerBosch/MBLBarometerBoschPeriodicAltitudeEvent.h; sourceTree = ""; }; - CE782EDB13AAB2925552025E053F7928 /* MBLNeopixel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLNeopixel.h; path = MetaWear/Classes/Modules/Neopixel/MBLNeopixel.h; sourceTree = ""; }; - CE7DF8C67A67FDC3166FF2004E33F270 /* MBLGyro.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGyro.h; path = MetaWear/Classes/Modules/Gyro/MBLGyro.h; sourceTree = ""; }; - CEB907B756FEC95ABE36EB6962A359B1 /* MBLOnDieTemperature0.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLOnDieTemperature0.m; path = MetaWear/Internal/Modules/Temperature/MBLOnDieTemperature0.m; sourceTree = ""; }; - CF31C98488A03AF1D8E488DD1D680615 /* MBLBitmaskEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBitmaskEvent.h; path = MetaWear/Internal/Modules/SensorFusion/MBLBitmaskEvent.h; sourceTree = ""; }; - CFD114275AF87D35C2037EFF0F9B077C /* MBLEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLEvent+Private.h"; path = "MetaWear/Internal/Core/MBLEvent+Private.h"; sourceTree = ""; }; - D006A70806095AADD36919E07D16E88B /* BFExecutor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BFExecutor.m; path = Bolts/Common/BFExecutor.m; sourceTree = ""; }; - D042F1A9160E0C2DD382751B794F95CF /* MBProgressHUD-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "MBProgressHUD-dummy.m"; sourceTree = ""; }; - D0AC0F7FEF3F08355FCF20E99657DD8F /* ColorPreviewWithHex.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPreviewWithHex.swift; path = FlexColorPicker/Classes/Controls/ColorPreviewWithHex.swift; sourceTree = ""; }; - D0BA3AA18F797CA8C3E4DEBA6DD071F4 /* Helpers.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Helpers.swift; path = Sources/SQLite/Helpers.swift; sourceTree = ""; }; - D1C71B13C43496337847E0080653C90C /* MBLAccelerometer+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometer+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/MBLAccelerometer+Private.h"; sourceTree = ""; }; - D1DC59226A6BE4F5117B51F1D275E92C /* MBLEntityModule+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLEntityModule+Private.h"; path = "MetaWear/Internal/Core/MBLEntityModule+Private.h"; sourceTree = ""; }; - D263E60F84C555442F3EAF5B1A62319D /* MBLData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLData.m; path = MetaWear/Classes/Core/MBLData.m; sourceTree = ""; }; - D329E9BD6CF1B08F9C596B19BA5717D0 /* FlexColorPicker-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FlexColorPicker-umbrella.h"; sourceTree = ""; }; - D340450AACFCF8501E977E327B72295E /* MBLAccelerometerBMI160+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBMI160+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMI160/MBLAccelerometerBMI160+Private.h"; sourceTree = ""; }; - D432760CFB31355CF1D7A1ED92629E19 /* MBLCommand.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLCommand.m; path = MetaWear/Internal/Modules/Command/MBLCommand.m; sourceTree = ""; }; - D44113003212D13E02B7FF7483FF3C2F /* MBLAccelerometerBMA255MotionEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBMA255MotionEvent.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMA255/MBLAccelerometerBMA255MotionEvent.m; sourceTree = ""; }; - D47CF02ABCBDAA6FB17E801921105666 /* MBLGyroBMI160DataReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGyroBMI160DataReadyEvent.h; path = MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160DataReadyEvent.h; sourceTree = ""; }; - D4A3E8010251664FDF4E101B79FE66C9 /* MBLDispatchQueue.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLDispatchQueue.m; path = MetaWear/Internal/Core/MBLDispatchQueue.m; sourceTree = ""; }; - D552F19EA6C6A6E324AD9F25F1386347 /* MBLRGBData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLRGBData+Private.h"; path = "MetaWear/Internal/Modules/Photometer/MBLRGBData+Private.h"; sourceTree = ""; }; - D69275F729CE8C895B6AEEB4E6E87236 /* MBLAccelerometerBoschFlatData+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBoschFlatData+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFlatData+Private.h"; sourceTree = ""; }; - D6986B32117757A4EC70935FF197BF31 /* MBLTestDebug.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLTestDebug.h; path = MetaWear/Internal/Modules/TestDebug/MBLTestDebug.h; sourceTree = ""; }; - D786128F75597E6534D0A3DE85100713 /* ControlWithThumbView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlWithThumbView.swift; path = FlexColorPicker/Classes/Controls/ControlWithThumbView.swift; sourceTree = ""; }; - D80477684FAEDE04B68CA136E5D1FC6F /* MBLModule+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLModule+Private.h"; path = "MetaWear/Internal/Core/MBLModule+Private.h"; sourceTree = ""; }; - D826EF23F09E0BE7A81DF628D497EE80 /* MBLSettings.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLSettings.h; path = MetaWear/Classes/Modules/Settings/MBLSettings.h; sourceTree = ""; }; - D85D1057312D207DA8D70181E021BD2C /* MBLConductance.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLConductance.h; path = MetaWear/Classes/Modules/Conductance/MBLConductance.h; sourceTree = ""; }; - D89AED1CFA1E87CC33F977C4257D8921 /* UIViewWithCommonInit.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIViewWithCommonInit.swift; path = FlexColorPicker/Classes/Views/UIViewWithCommonInit.swift; sourceTree = ""; }; - DA51B5CBA61A46D223389903588000E7 /* MBLGyroBMI160AxisReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGyroBMI160AxisReadyEvent.h; path = MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160AxisReadyEvent.h; sourceTree = ""; }; - DBC2489879DB2FD6A78ABBAA6A302EDD /* MBLNeopixel.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLNeopixel.m; path = MetaWear/Classes/Modules/Neopixel/MBLNeopixel.m; sourceTree = ""; }; - DC7BB01B837D04C70825A8DAF533EF2F /* MBLNeopixelStrand+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLNeopixelStrand+Private.h"; path = "MetaWear/Internal/Modules/Neopixel/MBLNeopixelStrand+Private.h"; sourceTree = ""; }; - DD57F735FE5083BD26D4558A14334EE2 /* MBLAccelerometerBMA255MotionEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerBMA255MotionEvent.h; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/AccelerometerBMA255/MBLAccelerometerBMA255MotionEvent.h; sourceTree = ""; }; - DE60CA9A1403AB574CE630E92B1D9A87 /* MBLTemperature+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLTemperature+Private.h"; path = "MetaWear/Internal/Modules/Temperature/MBLTemperature+Private.h"; sourceTree = ""; }; - DEF9607D057EEFF22A1079E9E3ACF6CB /* MBLAccelerometerData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerData.m; path = MetaWear/Classes/Modules/Accelerometer/MBLAccelerometerData.m; sourceTree = ""; }; - DEFB1FF91118F26DC9B2C7DB3F183EAF /* MBLPhotometerTCS3472Format.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLPhotometerTCS3472Format.h; path = MetaWear/Internal/Modules/Photometer/PhotometerTCS3472/MBLPhotometerTCS3472Format.h; sourceTree = ""; }; - E00038F84A6C775FE43D73FCB163BDFC /* MBLAmbientLightLTR329.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAmbientLightLTR329.h; path = MetaWear/Classes/Modules/AmbientLight/AmbientLightLTR329/MBLAmbientLightLTR329.h; sourceTree = ""; }; - E0365AA1E5BCF7893919B18CED0199C8 /* FTS4.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FTS4.swift; path = Sources/SQLite/Extensions/FTS4.swift; sourceTree = ""; }; - E091FF5FCF34D77B3F81C5E20BCD9DDA /* MBLPhotometerTCS3472.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLPhotometerTCS3472.h; path = MetaWear/Classes/Modules/Photometer/PhotometerTCS3472/MBLPhotometerTCS3472.h; sourceTree = ""; }; - E1C3A991414ED39811546573DA275F5E /* MBLMovingAverage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMovingAverage.h; path = MetaWear/Internal/Core/MBLMovingAverage.h; sourceTree = ""; }; - E217536EBC923746AA9E13572B239634 /* UIImageExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIImageExtension.swift; path = FlexColorPicker/Classes/Utilities/UIImageExtension.swift; sourceTree = ""; }; - E2DFA2FD74F0EF2EB5D0CDA3A3B98463 /* MBLAccelerometerBosch+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBosch+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBosch+Private.h"; sourceTree = ""; }; - E4BF4BB984F29F4878D167D143761F12 /* MBLBluetoothPeripheral.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLBluetoothPeripheral.h; path = MetaWear/Internal/Mocks/MBLBluetoothPeripheral.h; sourceTree = ""; }; - E596EEE3CD039BB60C73DA5353A84FB8 /* MBLMetaWearManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMetaWearManager.m; path = MetaWear/Classes/Core/MBLMetaWearManager.m; sourceTree = ""; }; - E5C4DDA6F69ECF8AEF12B4C8F399C412 /* MBLI2C.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLI2C.h; path = MetaWear/Classes/Modules/I2C/MBLI2C.h; sourceTree = ""; }; - E5F60FD4BCF56BE7DBDA9F7FFB76CED9 /* MBLGyroBMI160Format.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGyroBMI160Format.m; path = MetaWear/Internal/Modules/Gyro/GyroBMI160/MBLGyroBMI160Format.m; sourceTree = ""; }; - E5F91787B75837730129E0136066D012 /* RTree.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RTree.swift; path = Sources/SQLite/Extensions/RTree.swift; sourceTree = ""; }; - E62E73A944F0141732701B301FCFA95B /* Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Foundation.swift; path = Sources/SQLite/Foundation.swift; sourceTree = ""; }; - E6D0EB9A44103CC978560C08DA0B7308 /* bmi160.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = bmi160.h; path = MetaWear/Classes/Modules/Gyro/GyroBMI160/bmi160.h; sourceTree = ""; }; - E75D64B6623706FFFE53E3FCE670A8A0 /* MBLFirmwareUpdateInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLFirmwareUpdateInfo.m; path = MetaWear/Classes/Core/MBLFirmwareUpdateInfo.m; sourceTree = ""; }; - E7FB521DBD6D8988829ADAF5B7745088 /* MBLHygrometer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLHygrometer.m; path = MetaWear/Classes/Modules/Hygrometer/MBLHygrometer.m; sourceTree = ""; }; - E88E61270713AD28CFA48C2A09CE49B4 /* MBLNonVolatileState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLNonVolatileState.m; path = MetaWear/Internal/Core/MBLNonVolatileState.m; sourceTree = ""; }; - E8C10FD0F6E850F0512408F4C54A7DDD /* MBLMacro.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMacro.m; path = MetaWear/Internal/Modules/Macro/MBLMacro.m; sourceTree = ""; }; - E8F7A7C727EEC2172412B3E86EBA2AEF /* MBLAccelerometerBoschPackedDataReadyEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschPackedDataReadyEvent.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschPackedDataReadyEvent.m; sourceTree = ""; }; - E946D77D182D19C59CE1B9781394E3E5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; - E9D32DA90EED38D8CCAD848202DA24F0 /* StaticDataTableViewController.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = StaticDataTableViewController.modulemap; sourceTree = ""; }; - EB29DCAE32FC6159EB64F81BA7AFD2E6 /* MBLMockPeripheralFactory.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMockPeripheralFactory.h; path = MetaWear/Internal/Mocks/MBLMockPeripheralFactory.h; sourceTree = ""; }; - EB90F9440DC08AE2F3B7D4D666F1C6A8 /* MBLGPIOData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGPIOData.m; path = MetaWear/Internal/Modules/GPIO/MBLGPIOData.m; sourceTree = ""; }; - EBDAB5AEEC34E895F148807F2B35FEA1 /* MBLMacAddressFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMacAddressFormat.h; path = MetaWear/Internal/Core/MBLMacAddressFormat.h; sourceTree = ""; }; - ECFC551F2CBA394E30DF1EE1AAFA3851 /* MBLAccelerometerMMA8452QFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerMMA8452QFormat.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerMMA8452QFormat.m; sourceTree = ""; }; - EDBDC73FE0EB39A12FCDD97E86BC4491 /* MBLGPIOData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLGPIOData.h; path = MetaWear/Internal/Modules/GPIO/MBLGPIOData.h; sourceTree = ""; }; - EDF27B3F155EBBF966F5A3073CC9FDB9 /* MBLGravityFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLGravityFormat.m; path = MetaWear/Internal/Modules/SensorFusion/MBLGravityFormat.m; sourceTree = ""; }; - F008509C008A129206D0F8D7A25F0F74 /* BFTask+MBLExtensions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "BFTask+MBLExtensions.h"; path = "MetaWear/Classes/Categories/BFTask+MBLExtensions.h"; sourceTree = ""; }; - F0D701BF8EC069496B3C43FFCAAC84C8 /* MBLBarometer+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLBarometer+Private.h"; path = "MetaWear/Internal/Modules/Barometer/MBLBarometer+Private.h"; sourceTree = ""; }; - F19BA693EC7CE7E4E9C7B076C5F04974 /* StaticDataTableViewController-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "StaticDataTableViewController-umbrella.h"; sourceTree = ""; }; - F32D36EE8FB83CE82EF6360F883DFBC1 /* MBLQuaternionFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLQuaternionFormat.h; path = MetaWear/Internal/Modules/SensorFusion/MBLQuaternionFormat.h; sourceTree = ""; }; - F3DB26DAB32F9C5F472F75CC5E362FC3 /* MBLLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLLogger.h; path = MetaWear/Internal/Core/MBLLogger.h; sourceTree = ""; }; - F4BD0D899F13C1E8BFC73E4828D6F046 /* MetaWearPrivate-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "MetaWearPrivate-Info.plist"; sourceTree = ""; }; - F4C943574CDB8C520D4B4DF70780C177 /* FastCoding.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FastCoding.modulemap; sourceTree = ""; }; - F598E2DEAEF60BBC882738F3C5DE09C4 /* MBLNeopixelStrand.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLNeopixelStrand.h; path = MetaWear/Classes/Modules/Neopixel/MBLNeopixelStrand.h; sourceTree = ""; }; + B7C0CCB48AA3B057268428EC76303DFC /* accelerometer.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = accelerometer.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer.cpp"; sourceTree = ""; }; + B93A2C54055E5EF58D751DBE7B5E910B /* Executor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Executor.swift; path = Sources/BoltsSwift/Executor.swift; sourceTree = ""; }; + BA09431180E518370E3EE772A93D5E51 /* StaticDataTableViewController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = StaticDataTableViewController.h; sourceTree = ""; }; + BB063FD11A20E6D416272E5D2B00EA69 /* Bolts-Swift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Bolts-Swift.modulemap"; sourceTree = ""; }; + BBEB11AA8CDB2838B1357BC6178A45BC /* ColorPickerController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPickerController.swift; path = FlexColorPicker/Classes/ColorPickerController.swift; sourceTree = ""; }; + BD60D33F48C0ECCEE55F5066BBC70F65 /* Bolts-Swift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Bolts-Swift-prefix.pch"; sourceTree = ""; }; + C5293B3FCC547BFBC35595164998B542 /* Task+ContinueWith.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Task+ContinueWith.swift"; path = "Sources/BoltsSwift/Task+ContinueWith.swift"; sourceTree = ""; }; + C6DF3EAA69C656558C536D0C4839B924 /* SQLite.swift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SQLite.swift-Info.plist"; sourceTree = ""; }; + C7160A39D7E51C78C986E9646E89AEF3 /* Bolts-Swift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Bolts-Swift-dummy.m"; sourceTree = ""; }; + C972E5A00474059B4961ABCDC802DD81 /* FTS4.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FTS4.swift; path = Sources/SQLite/Extensions/FTS4.swift; sourceTree = ""; }; + CA18725CA461815A2D0005D908942870 /* barometer_bosch.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = barometer_bosch.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/barometer_bosch.cpp"; sourceTree = ""; }; + CA94324DB1D919071BFF47D44CFE22E0 /* version.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = version.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/version.cpp"; sourceTree = ""; }; + CB8613D5367B50EE420667B174EE11FF /* StaticDataTableViewController.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = StaticDataTableViewController.debug.xcconfig; sourceTree = ""; }; + CECA536350ADA0B8271E80F831A15FBA /* CircleShapedView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CircleShapedView.swift; path = FlexColorPicker/Classes/Views/CircleShapedView.swift; sourceTree = ""; }; + CF47640DFEBCE252FBAA774FBE6F42F1 /* ColorPaletteDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPaletteDelegate.swift; path = FlexColorPicker/Classes/ControlDelegates/ColorPaletteDelegate.swift; sourceTree = ""; }; + CF7FAC8D2FF0282B7BE0648778AFD80A /* FlexColorPicker.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FlexColorPicker.debug.xcconfig; sourceTree = ""; }; + D15B0AD76D08E576C8490AAE7DCB6FE4 /* HSBColor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HSBColor.swift; path = FlexColorPicker/Classes/HSBColor.swift; sourceTree = ""; }; + D26F31596C2054BEEE96EF39F830E211 /* LimitedGestureViewDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LimitedGestureViewDelegate.swift; path = FlexColorPicker/Classes/Utilities/LimitedGestureViewDelegate.swift; sourceTree = ""; }; + D2E936650895E5617726CF0BD2093EE0 /* DeviceInformation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DeviceInformation.swift; path = MetaWear/Core/DeviceInformation.swift; sourceTree = ""; }; + D4CA5689F63E231F411DB3897F60AC87 /* StaticDataTableViewController-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "StaticDataTableViewController-dummy.m"; sourceTree = ""; }; + D8BD1701596BB4A36A1619F7EBEA658E /* dataprocessor_config.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = dataprocessor_config.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor_config.cpp"; sourceTree = ""; }; + D8ED150D37C2259786E97A605A2E86B1 /* Bolts-Swift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Bolts-Swift.debug.xcconfig"; sourceTree = ""; }; + D931D5E916522AE487B7B84F28F872B2 /* Task+WhenAll.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Task+WhenAll.swift"; path = "Sources/BoltsSwift/Task+WhenAll.swift"; sourceTree = ""; }; + D9444C173037C985CFBA2F46F3F44477 /* accelerometer_bosch.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = accelerometer_bosch.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/accelerometer_bosch.cpp"; sourceTree = ""; }; + DA3630A278B75627E12EA0ECF03C448D /* UIImageExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UIImageExtension.swift; path = FlexColorPicker/Classes/Utilities/UIImageExtension.swift; sourceTree = ""; }; + DE7E756025845D5026763B716AB638B9 /* ColorPickerControllerProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPickerControllerProtocol.swift; path = FlexColorPicker/Classes/ColorPickerControllerProtocol.swift; sourceTree = ""; }; + E065478487EB7C68D6F625F7BF7A1DA6 /* AbstractColorControl.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AbstractColorControl.swift; path = FlexColorPicker/Classes/Controls/AbstractColorControl.swift; sourceTree = ""; }; + E22536D52AAC69C2C171FDAB5083E20B /* conductance.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = conductance.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/conductance.cpp"; sourceTree = ""; }; + E28ECBA4FAEB24259B3627D392FF0116 /* FlexColorPicker-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FlexColorPicker-Info.plist"; sourceTree = ""; }; + E5C7C98E5F43A5EDD0E9807FD85025C0 /* PaletteControls.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PaletteControls.swift; path = FlexColorPicker/Classes/Controls/PaletteControls.swift; sourceTree = ""; }; + E69724E22F6FC9383261352112F37AE7 /* ColorPreviewWithHex.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPreviewWithHex.swift; path = FlexColorPicker/Classes/Controls/ColorPreviewWithHex.swift; sourceTree = ""; }; + E9B1FC1E22EF18BD3AC50CE41FFB8FCF /* datasignal.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = datasignal.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/datasignal.cpp"; sourceTree = ""; }; + EAF29A6D0F8307E6A0D5A153E2F923D0 /* FlexColorPicker-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FlexColorPicker-prefix.pch"; sourceTree = ""; }; + EB80BE754ED06F30FA1BB8B69C24EBAA /* Statement.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Statement.swift; path = Sources/SQLite/Core/Statement.swift; sourceTree = ""; }; + EBA57D212A040C675CF8A6B7BDECCC7C /* GradientView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = FlexColorPicker/Classes/Views/GradientView.swift; sourceTree = ""; }; + EBFD3354E9C426820E89DEB251A57B3A /* Connection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Connection.swift; path = Sources/SQLite/Core/Connection.swift; sourceTree = ""; }; + EC6CF370DFBFD3CB24303396CF8216F2 /* Task.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Task.swift; path = Sources/BoltsSwift/Task.swift; sourceTree = ""; }; + ED32DC6A70AA2AEEB654F90782756768 /* LimitedGestureCircleView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LimitedGestureCircleView.swift; path = FlexColorPicker/Classes/Views/LimitedGestureCircleView.swift; sourceTree = ""; }; + EEAC79C3B86693633106577FAA144D37 /* switch.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = switch.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/sensor/cpp/switch.cpp"; sourceTree = ""; }; + F0346D8A0FC45B4B2E9A5BF43D1F1424 /* dataprocessor.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = dataprocessor.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/processor/cpp/dataprocessor.cpp"; sourceTree = ""; }; + F3476230912E363CE7F5285D6527EAE3 /* ColorPickerThumbView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorPickerThumbView.swift; path = FlexColorPicker/Classes/Views/ColorPickerThumbView.swift; sourceTree = ""; }; + F4D71AB128E0FE7EDC1B242118F6E638 /* MetaWear.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = MetaWear.modulemap; sourceTree = ""; }; F5FA45A44C42CC2CA3A324A3E914CE19 /* SQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F608D801CCBDDE5FA00277364777BE80 /* MBLStringData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLStringData.h; path = MetaWear/Classes/Core/MBLStringData.h; sourceTree = ""; }; - F64CD2286F8C395213E1759FB5D210A8 /* CustomFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomFunctions.swift; path = Sources/SQLite/Typed/CustomFunctions.swift; sourceTree = ""; }; - F715537652AB81FD9ECC102350E1CD57 /* MBLSensorFusion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLSensorFusion.m; path = MetaWear/Classes/Modules/SensorFusion/MBLSensorFusion.m; sourceTree = ""; }; - F767D6AABF23900614BC7666848C7158 /* MBLAccelerometerBoschTapEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschTapEvent.m; path = MetaWear/Classes/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschTapEvent.m; sourceTree = ""; }; - F80F0FF6C6D5436494E3102489E662BE /* MBLAccelerometerBoschFlatEvent+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLAccelerometerBoschFlatEvent+Private.h"; path = "MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschFlatEvent+Private.h"; sourceTree = ""; }; - F84B331B5D6AAF1548DD1BB004AE5C2A /* Bolts.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Bolts.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F85FE393EC8D5A5BB2C2B3BB82E4C961 /* MBLMechanicalSwitch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLMechanicalSwitch.m; path = MetaWear/Classes/Modules/MechanicalSwitch/MBLMechanicalSwitch.m; sourceTree = ""; }; - F861CFB25E168725F2FA7AB07557676C /* MBLSerial+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLSerial+Private.h"; path = "MetaWear/Internal/Modules/Serial/MBLSerial+Private.h"; sourceTree = ""; }; - F8B642B6E984F380366552C1C3AB5752 /* MBLiBeacon.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLiBeacon.h; path = MetaWear/Classes/Modules/iBeacon/MBLiBeacon.h; sourceTree = ""; }; - F903D70AD9EE4E936590A1F2EC246AAC /* MBLAccelerometerPackedDataReadyEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLAccelerometerPackedDataReadyEvent.h; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerPackedDataReadyEvent.h; sourceTree = ""; }; - FBB30E58B8EB0EB21BE9FA3DE85AF8D6 /* MBProgressHUD.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MBProgressHUD.debug.xcconfig; sourceTree = ""; }; - FBE2315754253B9086E8727EA5D32D39 /* SQLite.swift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SQLite.swift-dummy.m"; sourceTree = ""; }; - FC3480BE022D8E6D7401757ED8B81E47 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; }; - FC52BBDAC51F31E80A57E1857CF0AE49 /* MBLRegister.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLRegister.m; path = MetaWear/Classes/Core/MBLRegister.m; sourceTree = ""; }; - FD3580AA05CE67ED12CEDA2573B69C33 /* BFTask+MBLPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "BFTask+MBLPrivate.h"; path = "MetaWear/Internal/Categories/BFTask+MBLPrivate.h"; sourceTree = ""; }; - FD38F3710826BDB2D3C81503A2CFAD48 /* BFTask.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = BFTask.h; path = Bolts/Common/BFTask.h; sourceTree = ""; }; - FD5F594EA2EE25FD89526C65F52CEC13 /* MBLFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLFormat.m; path = MetaWear/Internal/Core/MBLFormat.m; sourceTree = ""; }; - FDBCB4D513E8E858685C0A0E1D33FD35 /* MBLMetaWearManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MBLMetaWearManager.h; path = MetaWear/Classes/Core/MBLMetaWearManager.h; sourceTree = ""; }; - FE35C2B58564FC49CA69375A23CB33E0 /* MBLExternalThermistor1.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLExternalThermistor1.m; path = MetaWear/Internal/Modules/Temperature/MBLExternalThermistor1.m; sourceTree = ""; }; - FE6D1D6FC47BBB89650B9555D22855C7 /* MBLDataSwitch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLDataSwitch.m; path = MetaWear/Classes/Core/MBLDataSwitch.m; sourceTree = ""; }; - FE708F2E2F9A1E68737F97B4C29E57FD /* MBLAccelerometerFreeFallEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerFreeFallEvent.m; path = MetaWear/Internal/Modules/Accelerometer/MMA8452Q/MBLAccelerometerFreeFallEvent.m; sourceTree = ""; }; - FECF0D6201B0367E4A4A6B183BDC70A5 /* MBLAmbientLight.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAmbientLight.m; path = MetaWear/Classes/Modules/AmbientLight/MBLAmbientLight.m; sourceTree = ""; }; - FF21E26B641B2F5997E7D0DB7EFD730B /* MBLProximity+Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "MBLProximity+Private.h"; path = "MetaWear/Internal/Modules/Proximity/MBLProximity+Private.h"; sourceTree = ""; }; - FF55FC4FE71555887D78514BC4977D65 /* MBLAccelerometerBoschOrientationEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = MBLAccelerometerBoschOrientationEvent.m; path = MetaWear/Internal/Modules/Accelerometer/AccelerometerBosch/MBLAccelerometerBoschOrientationEvent.m; sourceTree = ""; }; - FFDCC96BE3FFD250CD91415D4C8162F9 /* CoreFunctions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CoreFunctions.swift; path = Sources/SQLite/Typed/CoreFunctions.swift; sourceTree = ""; }; + FCD0E60673601418F91147C07E861F97 /* SQLite.swift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SQLite.swift-prefix.pch"; sourceTree = ""; }; + FDDBDDC69CDAD4981A3821042DABE063 /* SQLite.swift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SQLite.swift-umbrella.h"; sourceTree = ""; }; + FE3C58FBE30DA1BAAA46853AB653154E /* ColorSliderDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ColorSliderDelegate.swift; path = FlexColorPicker/Classes/ControlDelegates/ColorSliderDelegate.swift; sourceTree = ""; }; + FEEEB3439CFFFDE16B34BD12D5B91522 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; + FF048487264D96ECB101BAD6F14FB579 /* responseheader.cpp */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; name = responseheader.cpp; path = "MetaWear/MetaWear-SDK-Cpp/src/metawear/core/cpp/responseheader.cpp"; sourceTree = ""; }; + FF8666F601E6BBF1A8CF4356C49EC82D /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CoreBluetooth.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 027D1E80DE0AD8115B0EF3B90C9DAB38 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BBDF31B34E37575116AEDEBF2BB9B701 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 19EA8D7B4B1D3024E3727B542CCD89C6 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1093,11 +448,12 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 3427D5FAF7238C4B5B07F26129576E7A /* Frameworks */ = { + 3DD73F8FFEB15B96AB33B8A17DAB8123 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E429436B0DFEBCD3B38A92D86B128224 /* Foundation.framework in Frameworks */, + 208789A7951838C97BEEEEBD5FF50952 /* CoreBluetooth.framework in Frameworks */, + 1A8F21500DEEC319D3C71BCDA14D8465 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1109,21 +465,19 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 8BF55D61418E01E606930DE19C76D10C /* Frameworks */ = { + 646C45A726428B6E68D423DD13C842C7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CE5067B38ACA71E582DF300E3DCD7372 /* Foundation.framework in Frameworks */, + 74D9E0F3FAC53797E5F9894412582280 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - A38EDC82DFFEEE2A2C06452BCAF08334 /* Frameworks */ = { + 8BF55D61418E01E606930DE19C76D10C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - FF9FC0893F64401D9EC5702DB7DEE54F /* CoreBluetooth.framework in Frameworks */, - 95B164E33EC4430F4052E7AAB22DA85B /* CoreData.framework in Frameworks */, - C8FA535E3E3CA00982B7050BEDDE0786 /* Foundation.framework in Frameworks */, + CE5067B38ACA71E582DF300E3DCD7372 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1137,14 +491,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - D8739B7FA86987058BB9003084FC7234 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 7DA57DF234CFD29BAAB6761211D22ABA /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; E23FE1CF834589DAC05BDA1EFD7315AA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1153,655 +499,310 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - F8016C61CF40B45EA8222E137657E5F9 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 4FFF9461510B01AE1E38C236E459848B /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 02EAA74F652279D410C06AD7382A7567 /* Support Files */ = { + 0AD81B99962F214A7481D05DB5171CCA /* Core */ = { isa = PBXGroup; children = ( - 2E827CD701EF38921B89B7BC7DF0EE9D /* MBProgressHUD.modulemap */, - D042F1A9160E0C2DD382751B794F95CF /* MBProgressHUD-dummy.m */, - 3D1007461EE807A8FADC1771B6E82285 /* MBProgressHUD-Info.plist */, - 93473D232BB71FEE0EB8DC34DCE6C8B4 /* MBProgressHUD-prefix.pch */, - 5F05E3F8AB2E722ADB3A3663D0DE873B /* MBProgressHUD-umbrella.h */, - FBB30E58B8EB0EB21BE9FA3DE85AF8D6 /* MBProgressHUD.debug.xcconfig */, - 62BD501B622AE2197A8251EBEBC98B30 /* MBProgressHUD.release.xcconfig */, - ); - name = "Support Files"; - path = "../Target Support Files/MBProgressHUD"; + B7C0CCB48AA3B057268428EC76303DFC /* accelerometer.cpp */, + D9444C173037C985CFBA2F46F3F44477 /* accelerometer_bosch.cpp */, + 3B48995017BA31F28C04293A293DB8B0 /* accelerometer_mma8452q.cpp */, + ACF5B3235A355BACAD2D100F5491E44A /* ambientlight_ltr329.cpp */, + 65CD4D32CCEF7CD1945A9206364F5D59 /* anonymous_datasignal.cpp */, + A31050EA589DAF8798D4F5FD0C699B2A /* async_creator.cpp */, + CA18725CA461815A2D0005D908942870 /* barometer_bosch.cpp */, + 6830BF747190EDBF2EB01106C0C94705 /* Bridging.swift */, + 2B7CB030AD099F3C8A3F365D79A48586 /* cbindings.swift */, + 07EB6AC6BAB46765B87C1854FC9D24FA /* CBUUID.swift */, + 72F91017E90ACD4FCE83A3485695C412 /* colordetector_tcs34725.cpp */, + E22536D52AAC69C2C171FDAB5083E20B /* conductance.cpp */, + 2477E023C796D61FBF59A723CC673078 /* datainterpreter.cpp */, + F0346D8A0FC45B4B2E9A5BF43D1F1424 /* dataprocessor.cpp */, + D8BD1701596BB4A36A1619F7EBEA658E /* dataprocessor_config.cpp */, + E9B1FC1E22EF18BD3AC50CE41FFB8FCF /* datasignal.cpp */, + 202557B2F47A4E7B5134C438B511D6EE /* debug.cpp */, + D2E936650895E5617726CF0BD2093EE0 /* DeviceInformation.swift */, + 2F47F4AA73ACEAC9FDA41D36C0332414 /* dfu_operations.cpp */, + 204375FBD2222484868C2AE46A076980 /* dfu_operations_details.cpp */, + 5CC2C0DCF05FC714271C90C86A6877FC /* dfu_utility.cpp */, + 28A378F9A01525E97149ABB8DCA5B1CC /* event.cpp */, + 4E361A5F54DAAE628EE9C57E66FB6063 /* file_operations.cpp */, + 8E2005539348BC2EC04A37B194E1D027 /* gpio.cpp */, + 055FA51C8FB880D13FFBCA44BD83959E /* gyro_bosch.cpp */, + 88EF07E07BC8B02D7922894DD2D4FD83 /* haptic.cpp */, + 1315F41C173F3794DF812FFB6E4BABB1 /* humidity_bme280.cpp */, + 590BAB70520695F7005DBB2221F72974 /* ibeacon.cpp */, + 2DB10B9B88AEAF7203CF4E5E6BCED7DC /* led.cpp */, + 7E837DDBD7E6B0A0B51BCC223AB74E2F /* LogDelegate.swift */, + 8CD32BC358ADAD2D2224880C6512FE29 /* logging.cpp */, + 3589746F3729736D14CFCA7C05CDF29A /* macro.cpp */, + 9BB8A576C5797EB68CB23964A394D94C /* magnetometer_bmm150.cpp */, + 084321B9DB2861041514FA3802DBF807 /* MblMwGattChar.swift */, + 20B37E395C3B2DB48FE661BCCEB47093 /* memory.cpp */, + 99BD5F29CB67E3572EB2165C71C69402 /* MetaWear.swift */, + 9AB3434E3EC03D58E5256B36E21F667E /* metawearboard.cpp */, + 7E51668FB3B651E6FE54DCD75388792D /* MetaWearData.swift */, + 4E0DEB45E3FBA4102D9F9FB1D8E82D90 /* MetaWearScanner.swift */, + 89590357DAA3D6FE1273B2AA18B10370 /* miniz.cpp */, + 0835B59033E67470EFD8A9B7D3F477A1 /* moduleinfo.cpp */, + 8F89C30C49386D56C5D3FF459FA8B560 /* multichanneltemperature.cpp */, + 4904F9E5929463BAFB7240A014D562EF /* neopixel.cpp */, + 2B99CC70D3AFA59FB6FE09F278637FBC /* proximity_tsl2671.cpp */, + FF048487264D96ECB101BAD6F14FB579 /* responseheader.cpp */, + 3AA4B180B473FDCCAA0F33EDC10B353E /* sensor_fusion.cpp */, + 1761180BE85C04EE61182D0C9ECE6D82 /* serialpassthrough.cpp */, + 2B682398687C85519B90ED18DBEE7951 /* settings.cpp */, + 18A531C4413D4A9678D8FA425EA53734 /* String+VersionCompare.swift */, + EEAC79C3B86693633106577FAA144D37 /* switch.cpp */, + 41F889C88E2EAA1759E630D7B46E37AF /* task.cpp */, + 4C7E47F325908076A46464074F516599 /* threadpool.cpp */, + 1117B4651FA1A8584AA3B198D1592A04 /* timer.cpp */, + 00BDECD92C9D043B5AD82953B2BF82C2 /* utils.cpp */, + CA94324DB1D919071BFF47D44CFE22E0 /* version.cpp */, + ); + name = Core; sourceTree = ""; }; - 03EC0206D06725942989CDB567C1C58A /* FastCoding */ = { + 1D732D6D337256872DE562D7B8BB1CB4 /* PRTween */ = { isa = PBXGroup; children = ( - C7DC20CA8168B95E252E3D42883085AF /* FastCoder.h */, - 9F3FB7312B0FB66FA2194029BF866463 /* FastCoder.m */, - 77DE4CDD89FFEEC0AA7709EDCC2DE534 /* Support Files */, + B31634A27AC13E9EEE2F0989C18B1870 /* PRTween.h */, + 3505FB4027267F44B467A1CE3189BE2A /* PRTween.m */, + A8F2C63252A09E44D38172A5608073A1 /* PRTweenTimingFunctions.h */, + 18A738C86125947939188474A1E4339E /* PRTweenTimingFunctions.m */, + ED5DB584A69C48061635FA57282B79CC /* Support Files */, ); - path = FastCoding; - sourceTree = ""; - }; - 1539B1F586DAC585034E940DC4FADCDE /* iOS */ = { - isa = PBXGroup; - children = ( - 73446BDE690FF38C64E2D46A9E471DA0 /* CoreBluetooth.framework */, - FC3480BE022D8E6D7401757ED8B81E47 /* CoreData.framework */, - B1F094F5014C64256F003CA4D7015EEB /* CoreGraphics.framework */, - 68BCF0277E9B4A26623762CFDEF2D541 /* Foundation.framework */, - E946D77D182D19C59CE1B9781394E3E5 /* QuartzCore.framework */, - ); - name = iOS; + path = PRTween; sourceTree = ""; }; - 221BB630AC841890EE790B2A687505BA /* StaticDataTableViewController */ = { + 2667DEE9C0D81EFC156132A533BCCBE8 /* Support Files */ = { isa = PBXGroup; children = ( - 69873ABB652364D99E9A6C4958E48A7B /* StaticDataTableViewController.h */, - AD032BAD9297C34CC59A56B6F37632D8 /* StaticDataTableViewController.m */, - 9EEA01B60911BB3A23CDACF578B72E80 /* Support Files */, + 9B1BDA10EB511E35ECD6ED7664C4CEEE /* SQLite.swift.modulemap */, + A0883C90F4487E6DD44FF9DAE921E35B /* SQLite.swift-dummy.m */, + C6DF3EAA69C656558C536D0C4839B924 /* SQLite.swift-Info.plist */, + FCD0E60673601418F91147C07E861F97 /* SQLite.swift-prefix.pch */, + FDDBDDC69CDAD4981A3821042DABE063 /* SQLite.swift-umbrella.h */, + 44850702D275D1B542895C838EDE8E50 /* SQLite.swift.debug.xcconfig */, + 12B347F97086190A06909E4EC2E6D349 /* SQLite.swift.release.xcconfig */, ); - path = StaticDataTableViewController; + name = "Support Files"; + path = "../Target Support Files/SQLite.swift"; sourceTree = ""; }; - 2299F1874167340BC6CC947CA7017C14 /* Support Files */ = { + 2FF3C83271148BE1709009415BD76594 /* Support Files */ = { isa = PBXGroup; children = ( - 8962D19DDF25CA96D9564E5DF5B80EE2 /* PRTween.modulemap */, - 84ED3110C21AB37CCDDF68B23BA0B774 /* PRTween-dummy.m */, - 64CDB650D726216D211F98C83B8AEB07 /* PRTween-Info.plist */, - 080EAFE4FDF6348B7223C1C772604E15 /* PRTween-prefix.pch */, - 4CC217CF9EA007AD52303A46616501F0 /* PRTween-umbrella.h */, - 6C76C0FCB90D1002A9C4A440C1A2AA92 /* PRTween.debug.xcconfig */, - 7095B1A9FFD67603BD83BD4F313E1E8E /* PRTween.release.xcconfig */, + 036D251389EC6686A9FDFF11C295F0B4 /* FlexColorPicker.modulemap */, + 810843420244FD34B1DCCEF5EC203EEE /* FlexColorPicker-dummy.m */, + E28ECBA4FAEB24259B3627D392FF0116 /* FlexColorPicker-Info.plist */, + EAF29A6D0F8307E6A0D5A153E2F923D0 /* FlexColorPicker-prefix.pch */, + B3A2F747328473C2A352F6941CF34BD8 /* FlexColorPicker-umbrella.h */, + CF7FAC8D2FF0282B7BE0648778AFD80A /* FlexColorPicker.debug.xcconfig */, + 2491E935A0E23ED9309DF4C5E517694E /* FlexColorPicker.release.xcconfig */, ); name = "Support Files"; - path = "../Target Support Files/PRTween"; + path = "../Target Support Files/FlexColorPicker"; sourceTree = ""; }; - 41485077B80CE1F347C4C415877D3713 /* Pods */ = { + 34C97B38046C979256136FA8D2BF0A8D /* StaticDataTableViewController */ = { isa = PBXGroup; children = ( - F64F41A18CBF30CD3D299A3235EC0398 /* Bolts */, - 03EC0206D06725942989CDB567C1C58A /* FastCoding */, - A493AEAE083BF39BE3AFBDDDC4417859 /* FlexColorPicker */, - FF8E07DCF62AA305B5FFA360FB103F14 /* MBProgressHUD */, - 4F11C40C29A44FFB6A26AFC3E94336B2 /* MetaWearPrivate */, - D4FD9467328308C249FBD33E30E25316 /* PRTween */, - F9D232FA941EF706C5E8486D7E89079D /* SQLite.swift */, - 221BB630AC841890EE790B2A687505BA /* StaticDataTableViewController */, + BA09431180E518370E3EE772A93D5E51 /* StaticDataTableViewController.h */, + 23DD4B70DE016F8CD94A44AD063A8F60 /* StaticDataTableViewController.m */, + 5115FD2F8335AE62D17FAB06889DAA63 /* Support Files */, ); - name = Pods; + path = StaticDataTableViewController; sourceTree = ""; }; - 4592D033778BE14EE8F64BD5231305AD /* Support Files */ = { + 3CF0B2CF8BB80A261FF812291799A953 /* Support Files */ = { isa = PBXGroup; children = ( - 7CC753C6CEF0996735AB8C22A51FDF76 /* Bolts.modulemap */, - 3C6E172F7AFAEC647876724C2CDCD8E2 /* Bolts-dummy.m */, - 5CC113B94F2B618EE4AA6709AF7E01C7 /* Bolts-Info.plist */, - 3DEBDB14BDA140D4AF5011F56E278A27 /* Bolts-prefix.pch */, - 2F671A45BF53AE08C5B8E3BE22A901D1 /* Bolts-umbrella.h */, - 43968FC5841B33AC860F8B17B9CA2E76 /* Bolts.debug.xcconfig */, - 2DA2162B1DE380D357939F9498BD8311 /* Bolts.release.xcconfig */, + BB063FD11A20E6D416272E5D2B00EA69 /* Bolts-Swift.modulemap */, + C7160A39D7E51C78C986E9646E89AEF3 /* Bolts-Swift-dummy.m */, + 4359429DE1914ED1F6EAEE419A29AF4B /* Bolts-Swift-Info.plist */, + BD60D33F48C0ECCEE55F5066BBC70F65 /* Bolts-Swift-prefix.pch */, + 856008788ABB599F1BEA9ECE9C974858 /* Bolts-Swift-umbrella.h */, + D8ED150D37C2259786E97A605A2E86B1 /* Bolts-Swift.debug.xcconfig */, + 18D894726DE00A174BEAABE67F40DF6C /* Bolts-Swift.release.xcconfig */, ); name = "Support Files"; - path = "../Target Support Files/Bolts"; + path = "../Target Support Files/Bolts-Swift"; sourceTree = ""; }; - 48C1A04055E7ECAA4EE9A6866EB26C8F /* Support Files */ = { + 455C08ED32714656CD4B875BCA0F1DD5 /* Bolts-Swift */ = { isa = PBXGroup; children = ( - 3809ADBAC12D7B7A5F2BBDA7627FCEF2 /* SQLite.swift.modulemap */, - FBE2315754253B9086E8727EA5D32D39 /* SQLite.swift-dummy.m */, - 67FC590E9E7EF5DA3862AFD78F294140 /* SQLite.swift-Info.plist */, - BB91C79095FC4962E764219F9A601235 /* SQLite.swift-prefix.pch */, - 557E2DBC953B749080CCF587EB527F41 /* SQLite.swift-umbrella.h */, - 192865505A11585EE708054437C64D0B /* SQLite.swift.debug.xcconfig */, - 9E05B40C0330E22A967C1E33D89416D5 /* SQLite.swift.release.xcconfig */, - ); - name = "Support Files"; - path = "../Target Support Files/SQLite.swift"; + 47834DBA79AF16C25F6D7EA5E5155B13 /* Errors.swift */, + B93A2C54055E5EF58D751DBE7B5E910B /* Executor.swift */, + EC6CF370DFBFD3CB24303396CF8216F2 /* Task.swift */, + C5293B3FCC547BFBC35595164998B542 /* Task+ContinueWith.swift */, + 68C951AAE97E1F47CDEDF6CCF3B94C2A /* Task+Delay.swift */, + D931D5E916522AE487B7B84F28F872B2 /* Task+WhenAll.swift */, + 756D781D44346D6C9C684FFC30C24D2B /* Task+WhenAny.swift */, + 8ED97638BEF69DFDE5546F33EDDAFA5C /* TaskCompletionSource.swift */, + 3CF0B2CF8BB80A261FF812291799A953 /* Support Files */, + ); + path = "Bolts-Swift"; sourceTree = ""; }; - 4F11C40C29A44FFB6A26AFC3E94336B2 /* MetaWearPrivate */ = { + 50E013D50FCA0ABA3D13235A8296B2EC /* MBProgressHUD */ = { isa = PBXGroup; children = ( - F008509C008A129206D0F8D7A25F0F74 /* BFTask+MBLExtensions.h */, - 7B005DFE326C47396B8658C6BC3E3088 /* BFTask+MBLExtensions.m */, - FD3580AA05CE67ED12CEDA2573B69C33 /* BFTask+MBLPrivate.h */, - 654770BD0B9DFE0978C88E8FA6D5AE04 /* BFTask+MBLPrivate.m */, - E6D0EB9A44103CC978560C08DA0B7308 /* bmi160.h */, - 2645876D1AD9695760FD68927753D24E /* MBLAccelerometer.h */, - 5A1B6E114D5CB12C862036963DCB2390 /* MBLAccelerometer.m */, - D1C71B13C43496337847E0080653C90C /* MBLAccelerometer+Private.h */, - 92D515E4EBB8012585D33EBE80ABDE75 /* MBLAccelerometerAxisReadyEvent.h */, - 71CB5DA203DD44720C6516AE4751BDF8 /* MBLAccelerometerAxisReadyEvent.m */, - 0F71375DD28767C26672DFD841B1BE72 /* MBLAccelerometerBMA255.h */, - 25FA6D0F03DE44901187E3563AD33707 /* MBLAccelerometerBMA255.m */, - 2A6FFF11EC07CE95E9550644682930EE /* MBLAccelerometerBMA255+Private.h */, - DD57F735FE5083BD26D4558A14334EE2 /* MBLAccelerometerBMA255MotionEvent.h */, - D44113003212D13E02B7FF7483FF3C2F /* MBLAccelerometerBMA255MotionEvent.m */, - 10F5BAC0567A9C558CC3AB8CF1EE3D1A /* MBLAccelerometerBMA255MotionEvent+Private.h */, - C034BDE0E58F942489EF132FFE65CF95 /* MBLAccelerometerBMI160.h */, - 1A837EA4F931F8F22DB23E84BA700143 /* MBLAccelerometerBMI160.m */, - D340450AACFCF8501E977E327B72295E /* MBLAccelerometerBMI160+Private.h */, - 1292C8E610760DB6D2DAF8A9F2109BDE /* MBLAccelerometerBMI160MotionEvent.h */, - 8D812B690E5B0D2F8F5F6CAE1E33FB56 /* MBLAccelerometerBMI160MotionEvent.m */, - BE81BC86D60BB954223F36E9EBADEB9C /* MBLAccelerometerBMI160MotionEvent+Private.h */, - 857526C5F59A06EEAFB4093855DCF331 /* MBLAccelerometerBMI160StepEvent.h */, - 2BE3ABA4E60E29199045F2A64CD74F91 /* MBLAccelerometerBMI160StepEvent.m */, - 8E6A9A89A7A6D2068DA309A57810A3F3 /* MBLAccelerometerBosch.h */, - B6E391DFCD4A71DF7EA3A6D8477D386B /* MBLAccelerometerBosch.m */, - E2DFA2FD74F0EF2EB5D0CDA3A3B98463 /* MBLAccelerometerBosch+Private.h */, - 3B069E8C2577A06891520F8052F65562 /* MBLAccelerometerBoschAxisReadyEvent.h */, - 314B0529C31F19362B7AD83D00A099B7 /* MBLAccelerometerBoschAxisReadyEvent.m */, - 15F2D265A6C06CC541A908919C149B97 /* MBLAccelerometerBoschDataReadyEvent.h */, - AC09702064EE3145D24A7F67CEC32E08 /* MBLAccelerometerBoschDataReadyEvent.m */, - 5FC5822E40E89D5C92D574C41A031395 /* MBLAccelerometerBoschFlatData.h */, - 65D6DC10F5E74FFA08C8CED7FFFD778C /* MBLAccelerometerBoschFlatData.m */, - D69275F729CE8C895B6AEEB4E6E87236 /* MBLAccelerometerBoschFlatData+Private.h */, - B279E17CC4C99B56C4AB6FA7871B3A09 /* MBLAccelerometerBoschFlatEvent.h */, - 8C3FDF931FB3F22106AEB74ADE3EE6B0 /* MBLAccelerometerBoschFlatEvent.m */, - F80F0FF6C6D5436494E3102489E662BE /* MBLAccelerometerBoschFlatEvent+Private.h */, - 8B3A9FC030CAA3A37E8B12FB7E4DDA76 /* MBLAccelerometerBoschFlatFormat.h */, - 3F5F92185806E08CE8B628A488ACF9DE /* MBLAccelerometerBoschFlatFormat.m */, - 4C15691C1FD31BFF5F8FAFD44482CA17 /* MBLAccelerometerBoschFormat.h */, - 95F84F11F10A37945DEACE2F521BAF09 /* MBLAccelerometerBoschFormat.m */, - 83E4339E9413CB51E88384FD2BB24A82 /* MBLAccelerometerBoschLowOrHighGEvent.h */, - 0841698E1D51A9F98486360941631FC4 /* MBLAccelerometerBoschLowOrHighGEvent.m */, - 49DA9CBC33AA2FDF6359C8FD3F306800 /* MBLAccelerometerBoschLowOrHighGEvent+Private.h */, - 6A32380E9FDE7BF474147BE27EF6EA33 /* MBLAccelerometerBoschOrientationEvent.h */, - FF55FC4FE71555887D78514BC4977D65 /* MBLAccelerometerBoschOrientationEvent.m */, - 51983FC1E94C3A7B3263DD06D3CCB519 /* MBLAccelerometerBoschOrientationFormat.h */, - C2E15C7CAF839B548FEC8915238371BE /* MBLAccelerometerBoschOrientationFormat.m */, - 74CC7720DE0EECC6FADF0ADA2BBB29BA /* MBLAccelerometerBoschPackedDataReadyEvent.h */, - E8F7A7C727EEC2172412B3E86EBA2AEF /* MBLAccelerometerBoschPackedDataReadyEvent.m */, - 1279087722BFA08A2563C4186EA02B32 /* MBLAccelerometerBoschRMSFormat.h */, - 19C89EECF5C0B13F35AEEF99D8418005 /* MBLAccelerometerBoschRMSFormat.m */, - 8FED6CFDFA4AED3BC7EDB54252A9B78C /* MBLAccelerometerBoschTapEvent.h */, - F767D6AABF23900614BC7666848C7158 /* MBLAccelerometerBoschTapEvent.m */, - 24D99B6BC6E29F9502C48BAB16605393 /* MBLAccelerometerBoschTapEvent+Private.h */, - 97DE674DA17D28837EEE190D55B1C72C /* MBLAccelerometerData.h */, - DEF9607D057EEFF22A1079E9E3ACF6CB /* MBLAccelerometerData.m */, - 2B364C63A62EB39DC5DD8139922E3E5A /* MBLAccelerometerData+Private.h */, - 27375EFF0029352930FC350FA1958789 /* MBLAccelerometerDataReadyEvent.h */, - B60A4C304F52AA1358CD318BF8438FF7 /* MBLAccelerometerDataReadyEvent.m */, - A40DCE98EAF323F2D77DBC24BEA5D411 /* MBLAccelerometerFreeFallEvent.h */, - FE708F2E2F9A1E68737F97B4C29E57FD /* MBLAccelerometerFreeFallEvent.m */, - AEE6B2B57E2658D16BB004197E73ADB7 /* MBLAccelerometerMMA8452Q.h */, - 68DEBCDB3540DF8E8A66FBD60AA6EC1D /* MBLAccelerometerMMA8452Q.m */, - 1FD9FA47B74B1AC08CBDFD649C1EDBAF /* MBLAccelerometerMMA8452Q+Private.h */, - 0F61A31F5F27DBB0BD934BC6571F76C1 /* MBLAccelerometerMMA8452QFormat.h */, - ECFC551F2CBA394E30DF1EE1AAFA3851 /* MBLAccelerometerMMA8452QFormat.m */, - 7C98A12DCBC5C73CA0813B0F0BB29E4C /* MBLAccelerometerMMA8452QOrientationFormat.h */, - 8499C6937A05616246FD6735CF490211 /* MBLAccelerometerMMA8452QOrientationFormat.m */, - C3A391E839582AAF0BFB4FE1830EE8BE /* MBLAccelerometerMMA8452QRMSFormat.h */, - B60C6D4316257A8592A9C8FFD2E4C1D2 /* MBLAccelerometerMMA8452QRMSFormat.m */, - 3518CBD6D03CE59AEF5ED8F8A1AAB9BE /* MBLAccelerometerOrientationEvent.h */, - 5B024B6DFDED940969EFF42A43655986 /* MBLAccelerometerOrientationEvent.m */, - F903D70AD9EE4E936590A1F2EC246AAC /* MBLAccelerometerPackedDataReadyEvent.h */, - B134A1DB88245EF935E2BC1D6B053A2B /* MBLAccelerometerPackedDataReadyEvent.m */, - 09D173DEE35AC8F637F76E98BAA98367 /* MBLAccelerometerShakeEvent.h */, - 7AEF8FF9DDA0EA639C8A63DF8F3EAD02 /* MBLAccelerometerShakeEvent.m */, - 1BD01F654DE5D06ED7C89636CDE53A98 /* MBLAccelerometerTapEvent.h */, - 2467DB704F5E928FE637376D0A496718 /* MBLAccelerometerTapEvent.m */, - 31EB4B1CA22089606877D26BE732188B /* MBLAmbientLight.h */, - FECF0D6201B0367E4A4A6B183BDC70A5 /* MBLAmbientLight.m */, - B42FA1179121C2BACE59FD1E5CCD9D15 /* MBLAmbientLight+Private.h */, - E00038F84A6C775FE43D73FCB163BDFC /* MBLAmbientLightLTR329.h */, - 1C8F2D1B54544E1C5892E95341D19CB9 /* MBLAmbientLightLTR329.m */, - 30278A2896EBED27D7B8B4A499988944 /* MBLAnalytics.h */, - C3DBA18C39DFD63A6E34ED9F78739553 /* MBLAnalytics.m */, - 63F79A6649FBFB5574186379DCD1D421 /* MBLANCS.h */, - 579F7BDE884513135251D390A9416BBE /* MBLANCS.m */, - A4397048407923C022BF6296206C83C2 /* MBLANCSEventData.h */, - 5593CCBED8E4AE15625FF3ACD2A666C7 /* MBLANCSEventData.m */, - 396C92EDB59F8462AA3C5CF4A773E86A /* MBLANCSEventData+Private.h */, - A6D37657F3EE943952978BAB8DA03E58 /* MBLAnonymousEvent.h */, - 8AA5616E4E4280DA16737BF116DD49F6 /* MBLAnonymousEvent.m */, - 9D900690513FC59CD201C4FEC888AB9B /* MBLAnonymousEvent+Private.h */, - 7CFBCFD2BF9FC802D2DF954EBFF6CBAF /* MBLBarometer.h */, - 67E7ECC3E54031D450010ADCF4BE7A02 /* MBLBarometer.m */, - F0D701BF8EC069496B3C43FFCAAC84C8 /* MBLBarometer+Private.h */, - 44131CFFCDE00E71F5EACDF06483240F /* MBLBarometerBME280.h */, - 61EBB4660D809D8033457C2CE80411B9 /* MBLBarometerBME280.m */, - CD5BAE72308C847F0DDDC961B9D1F1EB /* MBLBarometerBMP280.h */, - 1A4226CABDC9A7A1AB311F018CC7FCFB /* MBLBarometerBMP280.m */, - CD543DD9A37CED8E5D798EE760111A9D /* MBLBarometerBosch.h */, - 73950693CB69C144751AB0335D5AF000 /* MBLBarometerBosch.m */, - 1455523005F45E1DEB1BF69539D10967 /* MBLBarometerBosch+Private.h */, - CE750EE45CE8CF012A77D168A395CC3A /* MBLBarometerBoschPeriodicAltitudeEvent.h */, - 9C42D16CF91748AA1CCEA014D3D93140 /* MBLBarometerBoschPeriodicAltitudeEvent.m */, - 31F2FE25B77174C58D106A70256387EB /* MBLBarometerBoschPeriodicPressureEvent.h */, - 4DD64AB34CC0A56FD03310D59BD66415 /* MBLBarometerBoschPeriodicPressureEvent.m */, - CF31C98488A03AF1D8E488DD1D680615 /* MBLBitmaskEvent.h */, - 59B5866AFB868B2385488D9FF72A80D8 /* MBLBitmaskEvent.m */, - 4E97D61EA17F90FA1A96C5EA492CA4FB /* MBLBluetoothCentral.h */, - 9A83AECEA017C91C9F5CBA32F375B09E /* MBLBluetoothCentralMock.h */, - 1A0AEDBAEC7541B87CE8246EF7E685BF /* MBLBluetoothCentralMock.m */, - E4BF4BB984F29F4878D167D143761F12 /* MBLBluetoothPeripheral.h */, - 99962F735427ACDF3EC96AB3A35302A3 /* MBLBluetoothPeripheralMock.h */, - 81186E6794F9E16E132D1042A3A7382D /* MBLBluetoothPeripheralMock.m */, - 532D7FCACBDEC3A993ACD5007C5C63B0 /* MBLCategoryLoader.h */, - 666047892D4382C05D1CA2A8AD020509 /* MBLCategoryLoader.m */, - 0035D91A4EFD0627194FE64A3B48F79F /* MBLCommand.h */, - D432760CFB31355CF1D7A1ED92629E19 /* MBLCommand.m */, - D85D1057312D207DA8D70181E021BD2C /* MBLConductance.h */, - 9C073299F231C20AA958CCE9BE21E29B /* MBLConductance.m */, - 23907A2905EA3FA33DADE5E90FC69BED /* MBLConductanceData.h */, - 79E7C3C9FA6588559703C398E7688432 /* MBLConductanceData.m */, - 9AEF92ED6E230F7C4BE4000DC9B2F37F /* MBLConstants.h */, - 67ABBB9175C1AB274D0D7EAA75F73CE3 /* MBLConstants.m */, - CA70F8707E848340FC61F67D2D09DA6C /* MBLConstants+Private.h */, - 3A0C1066A28DFD968093094A4002CDC2 /* MBLConversion.h */, - 68755AC626C33567BB3E422E830BFF81 /* MBLConversion.m */, - 8491C15C76BF353764E258E377D0C2E8 /* MBLCorrectedFormat.h */, - 4AE72B7641A8DE28BB231324BA8FA0C9 /* MBLCorrectedFormat.m */, - CD20F39380856BCE4A46A32AB8DD3FED /* MBLData.h */, - D263E60F84C555442F3EAF5B1A62319D /* MBLData.m */, - 0A80AAF5A16E49D99665CDBB7DB5F417 /* MBLData+Private.h */, - 66413B269210BA611B909CE76A0081F7 /* MBLDataProcessor.h */, - 4519EAF79C77387F18804362AB896741 /* MBLDataProcessor.m */, - ADE85F46048EC1F3C36566473CA0DD97 /* MBLDataSample.h */, - 2A92E56CD0DA9567C0D2C38269029A45 /* MBLDataSample.m */, - 7784E31355FEBC6941C37143FAD1BB78 /* MBLDataSample+Private.h */, - BC01372E68FAF8353E6B5FF3C839FE55 /* MBLDataSwitch.h */, - FE6D1D6FC47BBB89650B9555D22855C7 /* MBLDataSwitch.m */, - 5865681E3AF1BA1C5A344C7FAEADCD6E /* MBLDependentData.h */, - 710C8C193172A27E175ED44AD3F04CDD /* MBLDependentData.m */, - 1F8E304B92A2F672CC202EDC0422B1E9 /* MBLDeviceInfo.h */, - C36BCB63685C8F467D7666E915B25FE1 /* MBLDeviceInfo.m */, - C36B46123D96EED8AFC393D73A505F49 /* MBLDeviceLookup.h */, - 9719CDA5A212D1B94FE445E855713AE3 /* MBLDeviceLookup.m */, - 8626A34A32F4E09F7180102BDA29423B /* MBLDispatchQueue.h */, - D4A3E8010251664FDF4E101B79FE66C9 /* MBLDispatchQueue.m */, - 0D25B6E79539085C97CB8B9387F181B8 /* MBLDownloadOnlyEvent.h */, - 5B86A2EA02A200B150829527A34D0C29 /* MBLDownloadOnlyEvent.m */, - 595E3AE5886C8CFBDE5B91E71DF980BD /* MBLEntityEvent.h */, - 12800A27E25D3F547A046667FE9DAA03 /* MBLEntityEvent.m */, - 35847D051FF4AC1EA26B080D0C468C99 /* MBLEntityEvent+Private.h */, - 3BC4C89BFE4515AEAFA90A8F0A2DB780 /* MBLEntityModule.h */, - 0A32C7003976797CB7E261BC2F4EFA18 /* MBLEntityModule.m */, - D1DC59226A6BE4F5117B51F1D275E92C /* MBLEntityModule+Private.h */, - 3D4398BE85C107FC9E87B95339D7DECD /* MBLEulerAngleData.h */, - 38AC511C52A3160D8BFA36D301F88345 /* MBLEulerAngleData.m */, - B79044677BC189DBE3E11CA1A5D45456 /* MBLEulerAngleData+Private.h */, - 4466835466E43CAEA302DA6589EA68F8 /* MBLEulerFormat.h */, - BE11AF986689B3ACFB86F3F7A54B71B7 /* MBLEulerFormat.m */, - A3D03AEC363BD828752113CECC7C80C6 /* MBLEvent.h */, - 80177AF5756ECF16947D8BC3FB15DA32 /* MBLEvent.m */, - CFD114275AF87D35C2037EFF0F9B077C /* MBLEvent+Private.h */, - 0908E566C0DB4EF23AE31DF93476D076 /* MBLExternalThermistor.h */, - 9C5799488BC7801B1D24372B47401F65 /* MBLExternalThermistor.m */, - 2608EBF86FD05C8C65787DD976E8A7A3 /* MBLExternalThermistor0.h */, - CCF4AAB7D3A5091626ADDD67F202425B /* MBLExternalThermistor0.m */, - 519EE35C72315D1A7AADC923C91B38E7 /* MBLExternalThermistor1.h */, - FE35C2B58564FC49CA69375A23CB33E0 /* MBLExternalThermistor1.m */, - C9316C8FB669D06A57EB51231B16FFE5 /* MBLFilter.h */, - 79DAF916659E8B5554A2381CE21AEABA /* MBLFilter.m */, - 8B61285A50EC5FE9ABE7406F805BD7ED /* MBLFilter+Private.h */, - A97E33CBC9D1460FA0817700D3D58EFC /* MBLFirmwareBuild.h */, - A5DBB6C06E3DAB5CC269D3472516F20C /* MBLFirmwareBuild.m */, - 3F8D2F802D75DFA0F0B9B216784D8953 /* MBLFirmwareUpdateInfo.h */, - E75D64B6623706FFFE53E3FCE670A8A0 /* MBLFirmwareUpdateInfo.m */, - 5C7F2255FF56AF376C85585754EF2C3A /* MBLFirmwareUpdateManager.h */, - 897B8CDE723F546E2116F984DF33DF5C /* MBLFirmwareUpdateManager.m */, - 7EE225CB21810DD025D78280C1B2474F /* MBLFormat.h */, - FD5F594EA2EE25FD89526C65F52CEC13 /* MBLFormat.m */, - 513FAF97F4FE15694C4CF4A8304BBEF3 /* MBLGPIO.h */, - BFBCEE9347037627B22BCB8770DBE213 /* MBLGPIO.m */, - 6C9E7AAB9EDEB14A11FC03AB7D891254 /* MBLGPIO+Private.h */, - EDBDC73FE0EB39A12FCDD97E86BC4491 /* MBLGPIOData.h */, - EB90F9440DC08AE2F3B7D4D666F1C6A8 /* MBLGPIOData.m */, - 839C1FE41EFED619CF628B14E7A166FA /* MBLGPIOPin.h */, - 5381E2D2DD1B9D824DD465B2CF527DAB /* MBLGPIOPin.m */, - 2041271A141C45AC517D17888B5AB562 /* MBLGPIOPin+Private.h */, - 689DA3C1690AA04AD8F0B525102106FB /* MBLGPIOPinChangeEvent.h */, - 362DE09F372E1F53540DDE7687212B9C /* MBLGPIOPinChangeEvent.m */, - B1CD72E1EDED538FB7F734E6A318EEF1 /* MBLGravityFormat.h */, - EDF27B3F155EBBF966F5A3073CC9FDB9 /* MBLGravityFormat.m */, - CE7DF8C67A67FDC3166FF2004E33F270 /* MBLGyro.h */, - 5F5B2380B642EC90ACB0655B0A740AAC /* MBLGyro.m */, - 23A28F0383C296A9AB950400B3387147 /* MBLGyro+Private.h */, - 2CF9E215545AF0D84ECF3C631CC3958C /* MBLGyroBMI160.h */, - BEC5AC5CB64ED4E1F0FFADAA163F3A2F /* MBLGyroBMI160.m */, - 94F8B62730BE54CC80EFCB063CE8DB0A /* MBLGyroBMI160+Private.h */, - DA51B5CBA61A46D223389903588000E7 /* MBLGyroBMI160AxisReadyEvent.h */, - ADB19BA4C93D3926CE12B4649B33E5FE /* MBLGyroBMI160AxisReadyEvent.m */, - D47CF02ABCBDAA6FB17E801921105666 /* MBLGyroBMI160DataReadyEvent.h */, - 56CE0C94F84E1FF8FDAF0132715EE59D /* MBLGyroBMI160DataReadyEvent.m */, - 76048F5B3375D5784C0B5324D1BE08D7 /* MBLGyroBMI160Format.h */, - E5F60FD4BCF56BE7DBDA9F7FFB76CED9 /* MBLGyroBMI160Format.m */, - 39D64BE10B561A0D34719CA9330EB32E /* MBLGyroBMI160PackedDataReadyEvent.h */, - 081C57DE88C04918BB9D408885753169 /* MBLGyroBMI160PackedDataReadyEvent.m */, - 4C2249EBCE5DF74C7202C4C1603B5C78 /* MBLGyroData.h */, - 6A1E8DAD74C3585D5AF1D9889AB1298C /* MBLGyroData.m */, - 88A78BC9BED1903F288B99F8243780E3 /* MBLGyroData+Private.h */, - 8060AB9A8C984249C5C707878D88D5EC /* MBLHapticBuzzer.h */, - 79009A415E1CA0B87F12D4F51E03E275 /* MBLHapticBuzzer.m */, - ABF926A861C75B028D5DEEAA25BBED22 /* MBLHygrometer.h */, - E7FB521DBD6D8988829ADAF5B7745088 /* MBLHygrometer.m */, - 2D199B40598C2ED9D0CBE7BBB0823967 /* MBLHygrometer+Private.h */, - CA5DE9F1D46C8C7DACC2C1C6A06C1C70 /* MBLHygrometerBME280.h */, - BE3703D7CF94997EE0D61F4A95442741 /* MBLHygrometerBME280.m */, - 1DB3F0AF535DD95F163B334A50BC36DF /* MBLHygrometerBME280PeriodicHumidityEvent.h */, - AB7BB654211C9E0BD7A936321B39F4ED /* MBLHygrometerBME280PeriodicHumidityEvent.m */, - E5C4DDA6F69ECF8AEF12B4C8F399C412 /* MBLI2C.h */, - 8970EEE842F7C944B400E85182FA4D7E /* MBLI2C.m */, - 7965DF8D05996851B19C61D851F9D1D0 /* MBLI2CData.h */, - 2C46D371D69D1FF5F5FA74A437E899D3 /* MBLI2CData.m */, - 3A8C11505635DEA31ECB90490AD1B7C0 /* MBLI2CData+Private.h */, - F8B642B6E984F380366552C1C3AB5752 /* MBLiBeacon.h */, - 05FA13B1682546E889E7F5EF918EDEF5 /* MBLiBeacon.m */, - 837BDA0EFF5B420C1734354EE59F809C /* MBLLED.h */, - AFA6D3F966A7D6C6CC905F69C04ED4DF /* MBLLED.m */, - 832E6B3B6A39524018A87DF2CB10161D /* MBLLED+Private.h */, - F3DB26DAB32F9C5F472F75CC5E362FC3 /* MBLLogger.h */, - 80EF906667CF40840440B6176DB8E974 /* MBLLogger.m */, - 3ACCB93D2A72146FE33631D032901428 /* MBLLogging.h */, - B66025F0A7A7B300D691863FA50F11D7 /* MBLLogging.m */, - 3C4F3EEAA0ADC98A3D8086E8AA82416C /* MBLLoggingV0.h */, - 42E7ABDEEF2B747C41A103067522FC2D /* MBLLoggingV0.m */, - 177E694248790CEB1B03BC3481CFED6D /* MBLLoggingV1.h */, - 1B2496EFD101ED42CCB429E14049A6A6 /* MBLLoggingV1.m */, - AB8E8A0E6C5761A0D832978E831F8B7E /* MBLLoggingV2.h */, - 8201272484180FA4D05CA43D01CE4B97 /* MBLLoggingV2.m */, - EBDAB5AEEC34E895F148807F2B35FEA1 /* MBLMacAddressFormat.h */, - 311E32021E8602317EB6D1575470819D /* MBLMacAddressFormat.m */, - 89E9AD6A613937C723DAE21265CF0A32 /* MBLMacro.h */, - E8C10FD0F6E850F0512408F4C54A7DDD /* MBLMacro.m */, - 7AF74140BE838529FCBE559FF49324FE /* MBLMagnetometer.h */, - 1C7BB0D32F5255CE1D02B13A3FA4B89C /* MBLMagnetometer.m */, - 8C8165089578A149C045394501D28749 /* MBLMagnetometer+Private.h */, - 145C4BA58ECB001DD5537B43D7365413 /* MBLMagnetometerBMM150.h */, - 4FC26A49844C73557693D346B633ECF5 /* MBLMagnetometerBMM150.m */, - AFB4497D5CD9672F5C95C767490B8BE1 /* MBLMagnetometerBMM150+Private.h */, - B6E6F6428599AAF50B572B1FD082CE70 /* MBLMagnetometerBMM150Format.h */, - 567F029623C3C2A10DC63BEC9ED354CA /* MBLMagnetometerBMM150Format.m */, - 95E4D7D504BD6D0C20D213018DE0D8C9 /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.h */, - 4196509A0F6F6008BEA13E7494AE5C80 /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.m */, - 50B863789CB70C7BB079677C237AD2B1 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.h */, - 76BDD73914207FAFFF3E9CF5C71B1250 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.m */, - 55E0C2D944995BB40CFA9BD4DF56E8EC /* MBLMagnetometerData.h */, - 78BE644057CFCCF385C1B31DD709F1C6 /* MBLMagnetometerData.m */, - 4E1E7DEA33754A4BDE312E7F9208C89F /* MBLMagnetometerData+Private.h */, - 5447D64353ADF313B6DDA3764B0AA4ED /* MBLMechanicalSwitch.h */, - F85FE393EC8D5A5BB2C2B3BB82E4C961 /* MBLMechanicalSwitch.m */, - 5391ECE3ABD3B21D5B420350C96853A3 /* MBLMetaWear.h */, - C21E4B182C7E88A6C2637D759E596E90 /* MBLMetaWear.m */, - 820C5930C99368E34D4BA3FF59AB6DC8 /* MBLMetaWear+Private.h */, - FDBCB4D513E8E858685C0A0E1D33FD35 /* MBLMetaWearManager.h */, - E596EEE3CD039BB60C73DA5353A84FB8 /* MBLMetaWearManager.m */, - 02D36FC3DB28544278D49A5526ED7097 /* MBLMetaWearManager+Private.h */, - EB29DCAE32FC6159EB64F81BA7AFD2E6 /* MBLMockPeripheralFactory.h */, - BDCD67FA16C0A10BB731D87465C6E05F /* MBLMockPeripheralFactory.m */, - 48B07B0B83A11EC07DF4B3E6582A952A /* MBLMockUtils.h */, - 76E454A82BFF17A592A4B90B73930D61 /* MBLMockUtils.m */, - BF96EFA28DB351EBE7678639DBEEE959 /* MBLModule.h */, - 72F8368AD145B7E0B2F4F356CD3EF20C /* MBLModule.m */, - D80477684FAEDE04B68CA136E5D1FC6F /* MBLModule+Private.h */, - 74B21379AD8E4BA85136D6EA4099C510 /* MBLModuleInfo.h */, - 8AFF5162AB9978EB3C44DC08A7021F3F /* MBLModuleInfo.m */, - 4DD64C1100F3E64306313F24E970E06C /* MBLModuleMock.h */, - 9E6328E370911FF7407A878B58FBE742 /* MBLModuleMock.m */, - E1C3A991414ED39811546573DA275F5E /* MBLMovingAverage.h */, - 7B842C1CF9D05CBEB663920D19E57722 /* MBLMovingAverage.m */, - CE782EDB13AAB2925552025E053F7928 /* MBLNeopixel.h */, - DBC2489879DB2FD6A78ABBAA6A302EDD /* MBLNeopixel.m */, - 7FE83A6332BFB6ACF4D7F6098D332826 /* MBLNeopixel+Private.h */, - F598E2DEAEF60BBC882738F3C5DE09C4 /* MBLNeopixelStrand.h */, - 6A3A5964E423BCF12F97938C3CE21151 /* MBLNeopixelStrand.m */, - DC7BB01B837D04C70825A8DAF533EF2F /* MBLNeopixelStrand+Private.h */, - 7114D8A31D2986FB66EF6D7AE023531B /* MBLNonVolatileState.h */, - E88E61270713AD28CFA48C2A09CE49B4 /* MBLNonVolatileState.m */, - 8C1E3DBB7FF2A60BFDBFDCED8736F8C7 /* MBLNumericData.h */, - 4924598DFBB638C24E440E1CE354CBCB /* MBLNumericData.m */, - 6E243FEF6D81DE5AFC9EBD3BDA3C420C /* MBLNumericData+Private.h */, - 28D619B87C03D8885E04BDB6D3672B5B /* MBLNumericFormatter.h */, - 15DEFC6322F383667D9163F4CA090C54 /* MBLNumericFormatter.m */, - 8738C2009B7045C579D0696C83A180A4 /* MBLOnDieTemperature0.h */, - CEB907B756FEC95ABE36EB6962A359B1 /* MBLOnDieTemperature0.m */, - 7C8301370646F1F03A57FE5982C6618B /* MBLOrientationData.h */, - 6F276868A47C5827372AA153634270CD /* MBLOrientationData.m */, - 9E2EB1A561C2951A3F29D98C21C6D68F /* MBLOrientationData+Private.h */, - 8C228A5E96ACBA64A79B79955A47D11D /* MBLPhotometer.h */, - 0131DF0EF949A15A0646568D00541439 /* MBLPhotometer.m */, - 03AAABEF834082B42949BFF22663E639 /* MBLPhotometer+Private.h */, - E091FF5FCF34D77B3F81C5E20BCD9DDA /* MBLPhotometerTCS3472.h */, - 97A9BB5093D62A978475C22DC60FBAAC /* MBLPhotometerTCS3472.m */, - DEFB1FF91118F26DC9B2C7DB3F183EAF /* MBLPhotometerTCS3472Format.h */, - 15B1F99EC4F214371CF2234D359734D6 /* MBLPhotometerTCS3472Format.m */, - A74539E4276BAD6B5B7AD628754C5504 /* MBLProximity.h */, - 462DD61F30926FABAAD6EA3D27791201 /* MBLProximity.m */, - FF21E26B641B2F5997E7D0DB7EFD730B /* MBLProximity+Private.h */, - CAF56CC7BF0723A62B749CD5DF597DB7 /* MBLProximityTSL2671.h */, - 47D7B95DD4B4EA43332240D4AFBC5C9B /* MBLProximityTSL2671.m */, - 4466877CF34DEA4079247DFB20452293 /* MBLQuaternionData.h */, - 355BD6A3989345E5BAE24648E1B93CA0 /* MBLQuaternionData.m */, - CC01879C87DED7F6F3014CC9690267C2 /* MBLQuaternionData+Private.h */, - F32D36EE8FB83CE82EF6360F883DFBC1 /* MBLQuaternionFormat.h */, - 2754222A4444878B4FE2DFA4619E1593 /* MBLQuaternionFormat.m */, - 9DC7BF0532FFB6F12EAF271B32F7DF12 /* MBLRegister.h */, - FC52BBDAC51F31E80A57E1857CF0AE49 /* MBLRegister.m */, - C7516AC1991429F6A3B81EBCA1C708A3 /* MBLRegister+Private.h */, - 997426A3EEBF7C2EB7DE297CA7BC5413 /* MBLRGBData.h */, - 43A8C9E3945A6C2788CB41E514EEA131 /* MBLRGBData.m */, - D552F19EA6C6A6E324AD9F25F1386347 /* MBLRGBData+Private.h */, - 800CCDF7A423E20D6E58606E2618A753 /* MBLRMSAccelerometerData.h */, - 3754406911E8EE9E7F3A41663E738787 /* MBLRMSAccelerometerData.m */, - A50E162915108843410E01B430AFCF82 /* MBLRMSAccelerometerData+Private.h */, - 0F164C3F15CFB0FD52FD5C684DCE5CE9 /* MBLSensorFusion.h */, - F715537652AB81FD9ECC102350E1CD57 /* MBLSensorFusion.m */, - 2A6F4150D266A40B8F330513CCE21781 /* MBLSensorFusion+Private.h */, - 376008DE59AE2BE57F75A4D045ADCBDB /* MBLSerial.h */, - 6EDC6817E50BBE358090BE6382A9D43A /* MBLSerial.m */, - F861CFB25E168725F2FA7AB07557676C /* MBLSerial+Private.h */, - D826EF23F09E0BE7A81DF628D497EE80 /* MBLSettings.h */, - 87E0C59754C9E2B1A128BA2D4C6A24D4 /* MBLSettings.m */, - AD10C0FA17E34B86E7160A70689FBC3C /* MBLSettings+Private.h */, - 38F0F7A8A8D5D19437156CA5EE554129 /* MBLSPIData.h */, - A0BEA4B8CB2275B94D4A678EEA3F9726 /* MBLSPIData.m */, - 7622CCBF862B6B768ED7FBD7F3DA490F /* MBLSPIData+Private.h */, - F608D801CCBDDE5FA00277364777BE80 /* MBLStringData.h */, - 5FC1A99D023D267E648A3B2CCD8CC0F7 /* MBLStringData.m */, - 798B5C3BB9132B9FDB5D673145BEC855 /* MBLStringData+Private.h */, - A1B3444495ED8736F3DFC544DA9D9F22 /* MBLTemperature.h */, - 3546FE1448811DA0824B98448DE651B1 /* MBLTemperature.m */, - DE60CA9A1403AB574CE630E92B1D9A87 /* MBLTemperature+Private.h */, - 0CC9FC024573932A6B57179D1A27FBC1 /* MBLTemperatureV0.h */, - 448ECF74A645B4FA12173EB17977FD37 /* MBLTemperatureV0.m */, - AA41C9AFBA1DEDF1DB28131ED13B1416 /* MBLTemperatureV1.h */, - 72290EA994E18E954E95E198E4CF8270 /* MBLTemperatureV1.m */, - D6986B32117757A4EC70935FF197BF31 /* MBLTestDebug.h */, - 43A5D2835F778AEC4A8D236902ADAF29 /* MBLTestDebug.m */, - 221760E26EFB265491A7EB9E276FA14F /* MBLTimer.h */, - 34088EF7AE33D968FAB900636386D40C /* MBLTimer.m */, - 56864443F16243B0215C7D7BBA02BF12 /* MBLTimer+Private.h */, - CCBB7805806FF294F5264BA8413A9B60 /* MBLTimerEvent.h */, - 17F41492695945037081DBB883B13048 /* MBLTimerEvent.m */, - BF08C236AA2798EE30C42E2EED2C4F1A /* MBLTimerEvent+Private.h */, - 5EFE1999F17421FBBC0203397DD7308E /* MBLTriggeredRead.h */, - 821A25C88C6989010CF8A849993C7D4E /* MBLTriggeredRead.m */, - 4A521C64917321A402EE237FF16FD9B0 /* MetaWear.h */, - 38CFCDB0514EBAAEF4CEE12D05EE8109 /* mma8452q.h */, - F0D108DB2E0675D38D99D3169B04E2A8 /* Support Files */, - ); - path = MetaWearPrivate; + 0D0A860770A756701363AE4A26743663 /* MBProgressHUD.h */, + 93819BB5AB4610BFDF6F0FC2282E4DDE /* MBProgressHUD.m */, + CEA44ABE91A20A7B3BA5538376312D47 /* Support Files */, + ); + path = MBProgressHUD; sourceTree = ""; }; - 53F2503F1BF9315EAC94288E0106B8F3 /* Products */ = { + 5115FD2F8335AE62D17FAB06889DAA63 /* Support Files */ = { isa = PBXGroup; children = ( - F84B331B5D6AAF1548DD1BB004AE5C2A /* Bolts.framework */, - 7CDA43646778C7DF1FF0FA8624D6F105 /* FastCoding.framework */, - 741F9D3943FF7542B04631B29216270F /* FlexColorPicker.framework */, - 8B8FAB0D627B17EDE1366984278705D9 /* MBProgressHUD.framework */, - 3AB44C67614744596C398BB3B0F6913A /* MetaWear.framework */, - B6B2138B534DA2D64E869EF442A8C7D1 /* Pods_MusicalCaneGame.framework */, - 6E87F128D99E2CC3AFB7243CE45DE0C4 /* PRTween.framework */, - F5FA45A44C42CC2CA3A324A3E914CE19 /* SQLite.framework */, - 6F06C6D2A37B9901E2E3277EAA264539 /* StaticDataTableViewController.framework */, + 9857283877591447B1363F9BD57800B5 /* StaticDataTableViewController.modulemap */, + D4CA5689F63E231F411DB3897F60AC87 /* StaticDataTableViewController-dummy.m */, + 99752ACF6F055D42962C66A5DE6DF958 /* StaticDataTableViewController-Info.plist */, + 31224639020F2F283B2541B95F80CD64 /* StaticDataTableViewController-prefix.pch */, + 406C98AC09D595E5C506DE76BF364909 /* StaticDataTableViewController-umbrella.h */, + CB8613D5367B50EE420667B174EE11FF /* StaticDataTableViewController.debug.xcconfig */, + 2592765ADE2B014E4E4341340C29238A /* StaticDataTableViewController.release.xcconfig */, ); - name = Products; + name = "Support Files"; + path = "../Target Support Files/StaticDataTableViewController"; sourceTree = ""; }; - 5753804A428E2BC5247A12FD97CAAC81 /* Tasks */ = { + 5F18A0540D79EEFD592C66F2FCF90F88 /* MetaWear */ = { isa = PBXGroup; children = ( - 252750A7AFDD794CFFE923FCE3F738ED /* BFCancellationToken.h */, - A31D7E886BA2EE4D7FE6732E7F0F8C08 /* BFCancellationToken.m */, - 80F929B0B2C6125D7E424E4A8D45F92F /* BFCancellationTokenRegistration.h */, - A0C072E7EBB31D497A02922D12FFD0BF /* BFCancellationTokenRegistration.m */, - 2DD12BA668FAAE372DD539EC9C82734C /* BFCancellationTokenSource.h */, - A6080F0AAC1DB95455EDE9EF02DBBAF7 /* BFCancellationTokenSource.m */, - B634A03BAB223550C28DA4D4C43BCE38 /* BFExecutor.h */, - D006A70806095AADD36919E07D16E88B /* BFExecutor.m */, - FD38F3710826BDB2D3C81503A2CFAD48 /* BFTask.h */, - A75EEDEF0F8BD9F3DB6E1D7268D8C0E3 /* BFTask.m */, - 314B82F710899A1A23F5558B1E07BC30 /* BFTask+Exceptions.h */, - 163E1C0C54636289C825D0724BD976AF /* BFTask+Exceptions.m */, - 38AFE3A959AC36D6E49E405E5F9C6B1C /* BFTaskCompletionSource.h */, - 5B13756AF4593D9371410055A4AE2417 /* BFTaskCompletionSource.m */, - 917209A52726E7382B909C115B2A81F6 /* Bolts.h */, - 44B4B3FD98CDD35B0B752E3160CA04B3 /* Bolts.m */, - ); - name = Tasks; + 0AD81B99962F214A7481D05DB5171CCA /* Core */, + 66DA35F910D4CC6DBED44AF5CFFA662A /* Support Files */, + ); + path = MetaWear; sourceTree = ""; }; - 5EF776E5C81C32888AC92A7A08968A18 /* Support Files */ = { + 66DA35F910D4CC6DBED44AF5CFFA662A /* Support Files */ = { isa = PBXGroup; children = ( - 66E71F2FFA4B67A171FF369570E25CDA /* FlexColorPicker.modulemap */, - 1873C5BE50DCCCBECF6498A78492DFFC /* FlexColorPicker-dummy.m */, - 5BFC3E767B602E9CA2FA9B76A93CFEAA /* FlexColorPicker-Info.plist */, - A4308FFBA546624C19F8BA0E4F1211BB /* FlexColorPicker-prefix.pch */, - D329E9BD6CF1B08F9C596B19BA5717D0 /* FlexColorPicker-umbrella.h */, - 879B08BDF7758C925448C0BFEE3B29EB /* FlexColorPicker.debug.xcconfig */, - 4E38AEA2BBA3C0224D73CD1875E2B759 /* FlexColorPicker.release.xcconfig */, + F4D71AB128E0FE7EDC1B242118F6E638 /* MetaWear.modulemap */, + 650F4F40CE2E099A10834D340BBD9EDE /* MetaWear-dummy.m */, + 30031551201F975A50370A70C7E5A533 /* MetaWear-Info.plist */, + 2B3DFF34646C16CCCF89F9B271E9F3C5 /* MetaWear-prefix.pch */, + 50BDC1CDDC48EE3D660BD7653DA1A8B5 /* MetaWear-umbrella.h */, + B4DE3FB54847A63C86EC53E8DC8530D9 /* MetaWear.debug.xcconfig */, + 3EA827C8B3D6F7A27497CC460A903E67 /* MetaWear.release.xcconfig */, ); name = "Support Files"; - path = "../Target Support Files/FlexColorPicker"; + path = "../Target Support Files/MetaWear"; sourceTree = ""; }; - 726A02ACB586A4E4C9C13609AE164CB6 /* standard */ = { + 67BA03388A2AAF2ACDF56F6D251D8196 /* iOS */ = { isa = PBXGroup; children = ( - CAA0C8F987AE0F0506C0177F097AAFF2 /* AggregateFunctions.swift */, - B2AF51A650223D1BB2740F2372BE7090 /* Blob.swift */, - 58D0EAE6159180C30086D9739F578720 /* Coding.swift */, - 3900077A4790606E2800E23E5A2D5B1C /* Collation.swift */, - 51E77D088B0EFA67C576F729BE56D26F /* Connection.swift */, - FFDCC96BE3FFD250CD91415D4C8162F9 /* CoreFunctions.swift */, - F64CD2286F8C395213E1759FB5D210A8 /* CustomFunctions.swift */, - 8748CB4814020756E8C95D76D95C374A /* DateAndTimeFunctions.swift */, - 0181593C309048FF98276EB66B259494 /* Errors.swift */, - 35AA2A32130BF6780B993286A8E753CA /* Expression.swift */, - E62E73A944F0141732701B301FCFA95B /* Foundation.swift */, - 18BCDEA1BB8E632240F8D90D2EC39ABC /* fts3_tokenizer.h */, - E0365AA1E5BCF7893919B18CED0199C8 /* FTS4.swift */, - 81E83D2644E55250C1FBDC664E9792F8 /* FTS5.swift */, - D0BA3AA18F797CA8C3E4DEBA6DD071F4 /* Helpers.swift */, - C5ABAB1C2F3A3165F73F7E8EB46EDD41 /* Operators.swift */, - 0E4CB215E9687C8D91C0023BBD18DEF0 /* Query.swift */, - E5F91787B75837730129E0136066D012 /* RTree.swift */, - 47FE082C207AA18A150F1D2E98BBC37D /* Schema.swift */, - 6A43CC85B18E8ACDE0E384BBD649438C /* Setter.swift */, - 5C0E0758C2BBAC987D1296921D92C489 /* SQLite.h */, - 4BB39B281AA329E7B6D910316E475CB1 /* SQLite-Bridging.h */, - 8E9EBD3665678A28C911C3EC04616F63 /* SQLite-Bridging.m */, - 3415A4F0C188A771B1C86C144FE2C83F /* Statement.swift */, - 42C1C7FC4D76208F93B744123BD11F49 /* Value.swift */, + FF8666F601E6BBF1A8CF4356C49EC82D /* CoreBluetooth.framework */, + FEEEB3439CFFFDE16B34BD12D5B91522 /* CoreGraphics.framework */, + 7F488112BB40317E4F2DC31A347EE0E2 /* Foundation.framework */, + AC852EC78B5163CEFEF2E069E7BA4BE1 /* QuartzCore.framework */, ); - name = standard; + name = iOS; sourceTree = ""; }; - 77DE4CDD89FFEEC0AA7709EDCC2DE534 /* Support Files */ = { + 79D8BC9D6E476A06F5C3ABBE5EFB4F34 /* Products */ = { isa = PBXGroup; children = ( - F4C943574CDB8C520D4B4DF70780C177 /* FastCoding.modulemap */, - 374FAE1C230EFE649798C56C0E26D6E7 /* FastCoding-dummy.m */, - C831B453B2562186B3BDA684EA4ADFE6 /* FastCoding-Info.plist */, - 28443468DB16E07440FDC8A271BCB2A2 /* FastCoding-prefix.pch */, - B125C22BB5BB7A4B5211815B2C948FF4 /* FastCoding-umbrella.h */, - 4795D991502F3682F21E8D2935999466 /* FastCoding.debug.xcconfig */, - 252387757419D8BD4A16B5BB34E49F89 /* FastCoding.release.xcconfig */, + 1579A0986D70C32D7BED1A855C31EF4B /* BoltsSwift.framework */, + 741F9D3943FF7542B04631B29216270F /* FlexColorPicker.framework */, + 8B8FAB0D627B17EDE1366984278705D9 /* MBProgressHUD.framework */, + 7DF415FCE4EC0E6B83191E69BD55A61F /* MetaWear.framework */, + B6B2138B534DA2D64E869EF442A8C7D1 /* Pods_MusicalCaneGame.framework */, + 6E87F128D99E2CC3AFB7243CE45DE0C4 /* PRTween.framework */, + F5FA45A44C42CC2CA3A324A3E914CE19 /* SQLite.framework */, + 6F06C6D2A37B9901E2E3277EAA264539 /* StaticDataTableViewController.framework */, ); - name = "Support Files"; - path = "../Target Support Files/FastCoding"; + name = Products; sourceTree = ""; }; - 9EEA01B60911BB3A23CDACF578B72E80 /* Support Files */ = { + 90AC6DA14E2624900250B89E602AB85F /* standard */ = { isa = PBXGroup; children = ( - E9D32DA90EED38D8CCAD848202DA24F0 /* StaticDataTableViewController.modulemap */, - 4ACD94175F05C0E29F06F1928D1B2923 /* StaticDataTableViewController-dummy.m */, - 0507AD00A7595EC938575D499440F9BE /* StaticDataTableViewController-Info.plist */, - 906779D31DDEA2E5A800163C9367D00E /* StaticDataTableViewController-prefix.pch */, - F19BA693EC7CE7E4E9C7B076C5F04974 /* StaticDataTableViewController-umbrella.h */, - 79C8049DB69892D6593AFA7630E7932F /* StaticDataTableViewController.debug.xcconfig */, - 1A7459BA29DBA3A3E33E19765B2D9FE3 /* StaticDataTableViewController.release.xcconfig */, + 437E87C04ED10A10DE2D29A5C9F52D66 /* AggregateFunctions.swift */, + 81B6F2535F4EE9FA4A2315176F72688B /* Blob.swift */, + 41E0C85C4A4ABE0F68AAF0204AA763F8 /* Coding.swift */, + 9166DFD798F4A1606D7677551E3BD4EC /* Collation.swift */, + EBFD3354E9C426820E89DEB251A57B3A /* Connection.swift */, + 4DD70463C6C75069EC322EC78E9B74EF /* CoreFunctions.swift */, + 4855729C74F392B162E88C5A7F2DCEC2 /* CustomFunctions.swift */, + 851BADBA8A6FFFB5EC69F243391C54B4 /* DateAndTimeFunctions.swift */, + 17A9577AA604425FBE9BE62410A72561 /* Errors.swift */, + 2203E9635BA26459CD4A8B4E1B6D422B /* Expression.swift */, + 61AB588063CB884AA3519F769BE6EC82 /* Foundation.swift */, + B626047F766959C564A58087ACA58F97 /* fts3_tokenizer.h */, + C972E5A00474059B4961ABCDC802DD81 /* FTS4.swift */, + A47FEBBA1EE6AED3B97F30327C09C8E3 /* FTS5.swift */, + 88AB8185F159FC1D39C785EE66D4F58A /* Helpers.swift */, + 21FD84CE28F5CB27543CFC6542AC55F8 /* Operators.swift */, + 84BD1D885F3A9889ED88A68F6C0F90CB /* Query.swift */, + AEAB9015993CEBB553A0414679F7395D /* RTree.swift */, + 3F0F495A31ECF7DBEEB5653F543F0FF2 /* Schema.swift */, + 4DEDCD99D3FF6C87DA7A9228B2EA1B73 /* Setter.swift */, + 020CDAF0FC644CAA4F4AEE55474F33DE /* SQLite.h */, + 16C81353C57A838AFF0848801B54CC23 /* SQLite-Bridging.h */, + 619D18BEE833C4348EAF940808AA2B11 /* SQLite-Bridging.m */, + EB80BE754ED06F30FA1BB8B69C24EBAA /* Statement.swift */, + A735833176106989D12FB071A9461289 /* Value.swift */, ); - name = "Support Files"; - path = "../Target Support Files/StaticDataTableViewController"; + name = standard; sourceTree = ""; }; - A493AEAE083BF39BE3AFBDDDC4417859 /* FlexColorPicker */ = { + BA4F31F07263C99FC76E66D632A59F09 /* Frameworks */ = { isa = PBXGroup; children = ( - 8CE957C206AFAC66F176C3FF5B9495C7 /* AbstractColorControl.swift */, - 427AC7DC4569033439CABA2A30EC3326 /* AdjustedHitBoxColorControl.swift */, - 2419ECD02B38092140406C63872E7680 /* CGPointExtension.swift */, - 1A1ADBF675F2197D8BDC63EFAB0173CB /* CGRectExtension.swift */, - 70662CA035EC8936750C436C9EEA15B8 /* CircleShapedView.swift */, - 060C6688EBD31FE399EEF457BEB46DF4 /* ColorControl.swift */, - 52348E26326B74D99A9556A7F07D4FA4 /* ColorControlContentView.swift */, - 246B555E509917B4C8FE7D6D29CDD369 /* ColorPaletteControl.swift */, - C65A26A196DDDE0F69C776EA4C8AD4CD /* ColorPaletteDelegate.swift */, - 75A53299EEC86ABF9064680EBDC08974 /* ColorPickerController.swift */, - 0898A84F8AFB64E5EA38D125E0BA00AF /* ColorPickerControllerProtocol.swift */, - 0FD03161B220A16CBBC96747CD6F2A10 /* ColorPickerDelegate.swift */, - B4D3F620186E034F7C623B428D3109BD /* ColorPickerThumbView.swift */, - D0AC0F7FEF3F08355FCF20E99657DD8F /* ColorPreviewWithHex.swift */, - 9DEE8A761E6F3EFD39AC435300060A92 /* ColorSliderControl.swift */, - 6719B0DAAFC53A5D67AB989C9C97A924 /* ColorSliderDelegate.swift */, - C596C5CF2FA47DB70CEEBD0155610BCA /* ComponentSliderControls.swift */, - 80C1FEEFB923E9AAEF622948ABBBCB82 /* ComponentSliderDelegates.swift */, - D786128F75597E6534D0A3DE85100713 /* ControlWithThumbView.swift */, - C74601C377948832E851B19266E34DC4 /* CustomColorPickerViewController.swift */, - 2F05B37F717732E30D752E7C5D3F1201 /* DefaultColorPickerViewController.swift */, - 4D957451FBD0710F6B80E2099435B1C6 /* FlexColorPicker.h */, - 8EFA8BB36D6A79D6122BAADD7F82D3DC /* GradientView.swift */, - 5D1777824CD3B762DAC2AFDF780D0A21 /* HSBColor.swift */, - 465EF3F6218763ECC68FD764A9551DA5 /* LimitedGestureCircleView.swift */, - 8BAE0694187091665D4BF2CC5C546B7C /* LimitedGestureViewDelegate.swift */, - 47D66A0D6964C883FD711DA03207DC6F /* PaletteAwareScrollView.swift */, - B77B4FF4C17BA842D92B6BC68F66DCCD /* PaletteControls.swift */, - CA113996186396182E6481062F4AA736 /* RadialHSBPaletteDelegate.swift */, - 8BC8D097C45C807B6B0F9759CE423128 /* RectangularHSBPaletteDelegate.swift */, - A9D7C3BE275BD60DCC89C7FD4F387EFF /* UIColorExtension.swift */, - E217536EBC923746AA9E13572B239634 /* UIImageExtension.swift */, - 413CB9A1D4E013A9F23D12B5BC1A5D43 /* UIImageViewExtension.swift */, - B33CDBDF1B9436C886A3943A9CFBF3A7 /* UIViewExtension.swift */, - D89AED1CFA1E87CC33F977C4257D8921 /* UIViewWithCommonInit.swift */, - 5EF776E5C81C32888AC92A7A08968A18 /* Support Files */, + 67BA03388A2AAF2ACDF56F6D251D8196 /* iOS */, ); - path = FlexColorPicker; + name = Frameworks; sourceTree = ""; }; - B94D7768568A9992200DB461E8CF687F /* Frameworks */ = { + C20845A5E747009576D5E51AEDEFC5C8 /* FlexColorPicker */ = { isa = PBXGroup; children = ( - 1539B1F586DAC585034E940DC4FADCDE /* iOS */, + E065478487EB7C68D6F625F7BF7A1DA6 /* AbstractColorControl.swift */, + 4696B4A78EB5B5B2019A21FEF3C142FB /* AdjustedHitBoxColorControl.swift */, + 12FCF269555838BE1EB2EF3B8B421F09 /* CGPointExtension.swift */, + 7B4B70F59939EEA547A42705D781E63C /* CGRectExtension.swift */, + CECA536350ADA0B8271E80F831A15FBA /* CircleShapedView.swift */, + 8AFC83344D6B8191AE1C143E1E02E283 /* ColorControl.swift */, + 8CE762A6D7D985FF99D6392847EC42E8 /* ColorControlContentView.swift */, + 748E831377F55E2DEFF12C9EAD1EDA36 /* ColorPaletteControl.swift */, + CF47640DFEBCE252FBAA774FBE6F42F1 /* ColorPaletteDelegate.swift */, + BBEB11AA8CDB2838B1357BC6178A45BC /* ColorPickerController.swift */, + DE7E756025845D5026763B716AB638B9 /* ColorPickerControllerProtocol.swift */, + 006410209AFD050C6245CBD2BE792B3F /* ColorPickerDelegate.swift */, + F3476230912E363CE7F5285D6527EAE3 /* ColorPickerThumbView.swift */, + E69724E22F6FC9383261352112F37AE7 /* ColorPreviewWithHex.swift */, + 68270A8D2FCE48DD4B73F8783B5E0F17 /* ColorSliderControl.swift */, + FE3C58FBE30DA1BAAA46853AB653154E /* ColorSliderDelegate.swift */, + 1E82D7D0D2F0F702176329306077C600 /* ComponentSliderControls.swift */, + 0BF3CCEC8E1F6B5E65883ED9F6FBBC95 /* ComponentSliderDelegates.swift */, + 31C846A5D44EB3A55B8C787DC3D91CCF /* ControlWithThumbView.swift */, + 767F239AADD5DE5511FC5DB522D50055 /* CustomColorPickerViewController.swift */, + 922596DF6C398433B0444D3BB469CE7C /* DefaultColorPickerViewController.swift */, + 9E5CB155C33429C2CEA4B8DBAE6B5C05 /* FlexColorPicker.h */, + EBA57D212A040C675CF8A6B7BDECCC7C /* GradientView.swift */, + D15B0AD76D08E576C8490AAE7DCB6FE4 /* HSBColor.swift */, + ED32DC6A70AA2AEEB654F90782756768 /* LimitedGestureCircleView.swift */, + D26F31596C2054BEEE96EF39F830E211 /* LimitedGestureViewDelegate.swift */, + A69C3F124C8003BE9DD9E0B347B4B24C /* PaletteAwareScrollView.swift */, + E5C7C98E5F43A5EDD0E9807FD85025C0 /* PaletteControls.swift */, + 7B381E4993D646F1889B08E2056F6B10 /* RadialHSBPaletteDelegate.swift */, + 5741ABB2DC93CE21CD2A606D5DEEA17C /* RectangularHSBPaletteDelegate.swift */, + 97BE74803775549BE6BF46F72308B6C9 /* UIColorExtension.swift */, + DA3630A278B75627E12EA0ECF03C448D /* UIImageExtension.swift */, + 0F087B42BF52603BAF578654BF30C2B2 /* UIImageViewExtension.swift */, + 05CFF58B935C980A160C6C4D65A7CE00 /* UIViewExtension.swift */, + 1E9D2F75D9E329E80A4A9A2F989DDAC9 /* UIViewWithCommonInit.swift */, + 2FF3C83271148BE1709009415BD76594 /* Support Files */, ); - name = Frameworks; + path = FlexColorPicker; sourceTree = ""; }; CE16931CB4C8C530ED8D78C629B8261F /* Pods-MusicalCaneGame */ = { @@ -1821,78 +822,76 @@ path = "Target Support Files/Pods-MusicalCaneGame"; sourceTree = ""; }; - CF1408CF629C7361332E53B88F7BD30C = { + CEA44ABE91A20A7B3BA5538376312D47 /* Support Files */ = { isa = PBXGroup; children = ( - 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, - B94D7768568A9992200DB461E8CF687F /* Frameworks */, - 41485077B80CE1F347C4C415877D3713 /* Pods */, - 53F2503F1BF9315EAC94288E0106B8F3 /* Products */, - F36B2E8DD1947F80B5D1695F2D6743C3 /* Targets Support Files */, + 73ACA690A071AA3BE5E5B9F95806F095 /* MBProgressHUD.modulemap */, + 59EA51B0D70CEB18187D969528EF0418 /* MBProgressHUD-dummy.m */, + 0CDA1FE502B946D587F0D299109AD287 /* MBProgressHUD-Info.plist */, + 6C18FBB6DA4349BD98E91AC4F8B2CC45 /* MBProgressHUD-prefix.pch */, + 68A07C8AA447D9D1F965F51BFEA3D3B2 /* MBProgressHUD-umbrella.h */, + 7F27C589134A2FEE1DBD415460594611 /* MBProgressHUD.debug.xcconfig */, + 5349A2FBCECBAF0D2A07BF2B4B1861A7 /* MBProgressHUD.release.xcconfig */, ); + name = "Support Files"; + path = "../Target Support Files/MBProgressHUD"; sourceTree = ""; }; - D4FD9467328308C249FBD33E30E25316 /* PRTween */ = { - isa = PBXGroup; - children = ( - 6723B5F56E66FCC63A664969CF24F4DC /* PRTween.h */, - 862315B9E7FA3F370EF8449599E625A0 /* PRTween.m */, - 177961493C41A3EA823992816120FAEE /* PRTweenTimingFunctions.h */, - C7CFF911E5E62F4576D5F62C22700FF5 /* PRTweenTimingFunctions.m */, - 2299F1874167340BC6CC947CA7017C14 /* Support Files */, - ); - path = PRTween; - sourceTree = ""; - }; - F0D108DB2E0675D38D99D3169B04E2A8 /* Support Files */ = { + CF1408CF629C7361332E53B88F7BD30C = { isa = PBXGroup; children = ( - 15EAE4E3DFB78431354404D1917E8D9A /* MetaWearPrivate.modulemap */, - 9412CC7AD155C9478A8CAAC3A112EDDD /* MetaWearPrivate-dummy.m */, - F4BD0D899F13C1E8BFC73E4828D6F046 /* MetaWearPrivate-Info.plist */, - 63B6032E50F1902598BCFDCBF410C4DB /* MetaWearPrivate-prefix.pch */, - 4443E63922CECE498D2F090F518F1509 /* MetaWearPrivate-umbrella.h */, - 2B7F010F3BCC8E3ED586A840E274BACE /* MetaWearPrivate.debug.xcconfig */, - 493E9D78B13733C59AB3A986CB697840 /* MetaWearPrivate.release.xcconfig */, + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + BA4F31F07263C99FC76E66D632A59F09 /* Frameworks */, + D66CD622D1E5F3BF5B9D7F54F0A1FD07 /* Pods */, + 79D8BC9D6E476A06F5C3ABBE5EFB4F34 /* Products */, + F36B2E8DD1947F80B5D1695F2D6743C3 /* Targets Support Files */, ); - name = "Support Files"; - path = "../Target Support Files/MetaWearPrivate"; sourceTree = ""; }; - F36B2E8DD1947F80B5D1695F2D6743C3 /* Targets Support Files */ = { + D66CD622D1E5F3BF5B9D7F54F0A1FD07 /* Pods */ = { isa = PBXGroup; children = ( - CE16931CB4C8C530ED8D78C629B8261F /* Pods-MusicalCaneGame */, + 455C08ED32714656CD4B875BCA0F1DD5 /* Bolts-Swift */, + C20845A5E747009576D5E51AEDEFC5C8 /* FlexColorPicker */, + 50E013D50FCA0ABA3D13235A8296B2EC /* MBProgressHUD */, + 5F18A0540D79EEFD592C66F2FCF90F88 /* MetaWear */, + 1D732D6D337256872DE562D7B8BB1CB4 /* PRTween */, + EBE18244C1ACD16582C063B1E8A76F1C /* SQLite.swift */, + 34C97B38046C979256136FA8D2BF0A8D /* StaticDataTableViewController */, ); - name = "Targets Support Files"; + name = Pods; sourceTree = ""; }; - F64F41A18CBF30CD3D299A3235EC0398 /* Bolts */ = { + EBE18244C1ACD16582C063B1E8A76F1C /* SQLite.swift */ = { isa = PBXGroup; children = ( - 4592D033778BE14EE8F64BD5231305AD /* Support Files */, - 5753804A428E2BC5247A12FD97CAAC81 /* Tasks */, + 90AC6DA14E2624900250B89E602AB85F /* standard */, + 2667DEE9C0D81EFC156132A533BCCBE8 /* Support Files */, ); - path = Bolts; + path = SQLite.swift; sourceTree = ""; }; - F9D232FA941EF706C5E8486D7E89079D /* SQLite.swift */ = { + ED5DB584A69C48061635FA57282B79CC /* Support Files */ = { isa = PBXGroup; children = ( - 726A02ACB586A4E4C9C13609AE164CB6 /* standard */, - 48C1A04055E7ECAA4EE9A6866EB26C8F /* Support Files */, + 9F959FABCF6DA4F1D78ED752EDBFA470 /* PRTween.modulemap */, + AC214CCB2D7EC6565F37289452B522FE /* PRTween-dummy.m */, + 6CC590A92CBE7E54F981E383DAB2F33D /* PRTween-Info.plist */, + 848304F115E7770A6DA90BE2C0D9804B /* PRTween-prefix.pch */, + 80A006ECE0C1D98020B9C6469CBAEF3A /* PRTween-umbrella.h */, + 6DCABDA1D6ACE795F49425A95926630A /* PRTween.debug.xcconfig */, + 33D59C5EE9504CAE85DD5EC3A8B2619D /* PRTween.release.xcconfig */, ); - path = SQLite.swift; + name = "Support Files"; + path = "../Target Support Files/PRTween"; sourceTree = ""; }; - FF8E07DCF62AA305B5FFA360FB103F14 /* MBProgressHUD */ = { + F36B2E8DD1947F80B5D1695F2D6743C3 /* Targets Support Files */ = { isa = PBXGroup; children = ( - 799D9302D1CE2454BF686DF875D0320A /* MBProgressHUD.h */, - 3504F10AAE9AFDB28FCB395022D5FE8C /* MBProgressHUD.m */, - 02EAA74F652279D410C06AD7382A7567 /* Support Files */, + CE16931CB4C8C530ED8D78C629B8261F /* Pods-MusicalCaneGame */, ); - path = MBProgressHUD; + name = "Targets Support Files"; sourceTree = ""; }; /* End PBXGroup section */ @@ -1918,224 +917,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 47ADB6E85546F0E00B11725E4D5A1858 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - AD51632D719A7A4FF25F29E6F7AA2288 /* BFTask+MBLExtensions.h in Headers */, - B07A78B35592EF6032FAE5A46F17DBF8 /* BFTask+MBLPrivate.h in Headers */, - FA2CAF4E18084BB84CF1087AF8AE8385 /* bmi160.h in Headers */, - 6B3471E60CC94FA3F906BD9CBCBF02BD /* MBLAccelerometer.h in Headers */, - 43092322CA985D0BA07B0354746E3EF9 /* MBLAccelerometer+Private.h in Headers */, - 9C9177A9F9FE48904009162459EAF98B /* MBLAccelerometerAxisReadyEvent.h in Headers */, - C2D5A24514DAE62B1EF5E13515CF486A /* MBLAccelerometerBMA255.h in Headers */, - B083234300A1D900612C5CDE2B681CCF /* MBLAccelerometerBMA255+Private.h in Headers */, - 8000EF1A3B7082727F948EFCD057BC3D /* MBLAccelerometerBMA255MotionEvent.h in Headers */, - 4332541495D7A23452A6A579D2160011 /* MBLAccelerometerBMA255MotionEvent+Private.h in Headers */, - 887203AE60FE7550F331465185ABA2B9 /* MBLAccelerometerBMI160.h in Headers */, - EF2F05C845EF1AEE3585FB4436352D52 /* MBLAccelerometerBMI160+Private.h in Headers */, - A3DA1CDE4325738D463013CBEC8AF645 /* MBLAccelerometerBMI160MotionEvent.h in Headers */, - F346385538DC01D7451F3C8D5580E2C5 /* MBLAccelerometerBMI160MotionEvent+Private.h in Headers */, - 94D04C8948D2387D796EBE1AE39E6DEE /* MBLAccelerometerBMI160StepEvent.h in Headers */, - FCE5E614A5F6D50D8C24CA228507BB20 /* MBLAccelerometerBosch.h in Headers */, - E81A68AC1FE467D049830BEBB84666F6 /* MBLAccelerometerBosch+Private.h in Headers */, - 72D3DBA694CFA9FFFC3E4353F3F74214 /* MBLAccelerometerBoschAxisReadyEvent.h in Headers */, - 0E6D8BFE0AE233753BCBDCA514A74C0E /* MBLAccelerometerBoschDataReadyEvent.h in Headers */, - D12E81F7891DD3DAA4A2CDEF773B49FD /* MBLAccelerometerBoschFlatData.h in Headers */, - 81B744C4FC968FB189399EE1B8E27A35 /* MBLAccelerometerBoschFlatData+Private.h in Headers */, - 53BF73FDAB4554F33A0B48DF814C0BC5 /* MBLAccelerometerBoschFlatEvent.h in Headers */, - 9C490FA55D8BA12069809F6A90134B09 /* MBLAccelerometerBoschFlatEvent+Private.h in Headers */, - F19E5EBCE21503E50F1443658CDE1221 /* MBLAccelerometerBoschFlatFormat.h in Headers */, - DB604C3949DB26DDCA99622F1D4DD31F /* MBLAccelerometerBoschFormat.h in Headers */, - 6AF54273822C94E2D534936CAB08A4E5 /* MBLAccelerometerBoschLowOrHighGEvent.h in Headers */, - 7FD8E0630377995AB01E23C7CAE0BDDD /* MBLAccelerometerBoschLowOrHighGEvent+Private.h in Headers */, - B6BAFAFFBA7FD1CF919F4964B7B68C89 /* MBLAccelerometerBoschOrientationEvent.h in Headers */, - A77115FEBD116A1E840ABB370B12CD60 /* MBLAccelerometerBoschOrientationFormat.h in Headers */, - 9E31D1EE91E56CC69F7F927F2AFD2BCF /* MBLAccelerometerBoschPackedDataReadyEvent.h in Headers */, - 14E6067619010FD3F365BAAF05B78B58 /* MBLAccelerometerBoschRMSFormat.h in Headers */, - F5A65785CD828CC0E12B4AD0E9686FF9 /* MBLAccelerometerBoschTapEvent.h in Headers */, - 7BB6A740AC730A49858F768945438686 /* MBLAccelerometerBoschTapEvent+Private.h in Headers */, - 0A9D62EE02E8812CE4625F142296428B /* MBLAccelerometerData.h in Headers */, - 4F3D3E2B42F11AD0C43C29BB45443D5F /* MBLAccelerometerData+Private.h in Headers */, - 1BF7821F0E1AE58CCF889268894ECEFE /* MBLAccelerometerDataReadyEvent.h in Headers */, - EAE0C24ACB689B64AC07E30A7B90506F /* MBLAccelerometerFreeFallEvent.h in Headers */, - 52A63DD22AEBB030D3112A41DABCD95B /* MBLAccelerometerMMA8452Q.h in Headers */, - 58EC2EF024941BC8E4FF4FE9F2698C14 /* MBLAccelerometerMMA8452Q+Private.h in Headers */, - 1139BBBBBAF0F3DD5D3E76D4AAE74DAE /* MBLAccelerometerMMA8452QFormat.h in Headers */, - 3B3F2F93DC339D289C849C393B9B1A70 /* MBLAccelerometerMMA8452QOrientationFormat.h in Headers */, - 43B68D64024BBB36520CCFF34D2CC1D8 /* MBLAccelerometerMMA8452QRMSFormat.h in Headers */, - 95007531A7D7167B8E2A934058E19D4B /* MBLAccelerometerOrientationEvent.h in Headers */, - AD3FFB62B0671B9D701C82E400B518AF /* MBLAccelerometerPackedDataReadyEvent.h in Headers */, - 746969B5E2FFE91B27C98D9D4CE01AFC /* MBLAccelerometerShakeEvent.h in Headers */, - A4FDC30E169690FDF1137D3E484D6567 /* MBLAccelerometerTapEvent.h in Headers */, - 07BA3B075F88C2170165585E0D3009C1 /* MBLAmbientLight.h in Headers */, - F337804A9799941C65D95D42EBD6277F /* MBLAmbientLight+Private.h in Headers */, - 0EDB699967ABEB02EB092AF24EE82293 /* MBLAmbientLightLTR329.h in Headers */, - 3DCB3952569C4270BF3C3E92B3DDB02B /* MBLAnalytics.h in Headers */, - 61C2B0B2A307903749C1D83DF203718B /* MBLANCS.h in Headers */, - C3A54BCAFE3C26E876B0748AE7EC1FE7 /* MBLANCSEventData.h in Headers */, - ED14B2DCB2151BDE96F3B95A1B6199C4 /* MBLANCSEventData+Private.h in Headers */, - D7277DD485764C26A4CC92D429A10882 /* MBLAnonymousEvent.h in Headers */, - DD5561CCF8DAAB73DC865462498DD77F /* MBLAnonymousEvent+Private.h in Headers */, - 6C91E3F5317327819188F3D00EC7B1CC /* MBLBarometer.h in Headers */, - 5B825EBBB25135A58E16E91C69ABCFCA /* MBLBarometer+Private.h in Headers */, - 5A1A16EBF2EE42DA6743EAA3004201BF /* MBLBarometerBME280.h in Headers */, - 2F5EB691F51632E5A37FA3F67CACDA97 /* MBLBarometerBMP280.h in Headers */, - 63088E344259927A411F55D1F5E52D68 /* MBLBarometerBosch.h in Headers */, - 08A965D1BCE12AE43CD46A1227E1C341 /* MBLBarometerBosch+Private.h in Headers */, - 62E75F5D23D9CF185B86551D0FB03ACE /* MBLBarometerBoschPeriodicAltitudeEvent.h in Headers */, - 65C13E997A2C177271DAE0308C22194A /* MBLBarometerBoschPeriodicPressureEvent.h in Headers */, - 16D461686E7092213D7E9926341FC656 /* MBLBitmaskEvent.h in Headers */, - 43FDD430CD293526E377E52D4573AF34 /* MBLBluetoothCentral.h in Headers */, - DA6409688B75D28260A57FCCD28AE71F /* MBLBluetoothCentralMock.h in Headers */, - 8F5046755779521DD7851754F69CE072 /* MBLBluetoothPeripheral.h in Headers */, - 0B7228B73B7A2204932286C042D42E4E /* MBLBluetoothPeripheralMock.h in Headers */, - 7CC030499CF261BEECAA968D4EC0AA3E /* MBLCategoryLoader.h in Headers */, - FC41A374495D394E691F3F96A64128F9 /* MBLCommand.h in Headers */, - 1749A31535DF81B1B3E075192D849765 /* MBLConductance.h in Headers */, - 7971E28FF50B61F003E3D3E1DE24D2C2 /* MBLConductanceData.h in Headers */, - FDA89C4D6465835B38D1BEA06158B884 /* MBLConstants.h in Headers */, - 9604CF7D4C4928BAFA81B3F8B5819F32 /* MBLConstants+Private.h in Headers */, - 9F180A87AEEE03366E3C6E4A673799AD /* MBLConversion.h in Headers */, - 0D61EF001DF1E45F9956DFCB75B21362 /* MBLCorrectedFormat.h in Headers */, - 5777482CB97E20747EED2860DCC0078F /* MBLData.h in Headers */, - 941FDF7E12A88B98C7587E283CACBDF4 /* MBLData+Private.h in Headers */, - 91ACA3242477717D677C467C3D4EE04E /* MBLDataProcessor.h in Headers */, - 108F412D144ABE030AEA38504E1DF359 /* MBLDataSample.h in Headers */, - 3EDCEA8E82B93C08617911C308E2B087 /* MBLDataSample+Private.h in Headers */, - D10A4C1E78E0103E99AF753A4F9D47E4 /* MBLDataSwitch.h in Headers */, - BB765876090DBA0C76F7EB8D7BD4DE61 /* MBLDependentData.h in Headers */, - AC681AA08911682051FC6AD79308EDA5 /* MBLDeviceInfo.h in Headers */, - 6947B5E5DEFD4E9FAE8C70146D05AD09 /* MBLDeviceLookup.h in Headers */, - BD3B53AE09FC635515D7E8669A876A34 /* MBLDispatchQueue.h in Headers */, - 869D4F01EE7471735EEB2E3DE112A586 /* MBLDownloadOnlyEvent.h in Headers */, - 3CB259984A8E20104D9EEF6CD36FA626 /* MBLEntityEvent.h in Headers */, - B72A378B5FA47A57E69BCEF5FEA70E92 /* MBLEntityEvent+Private.h in Headers */, - 54D4ADE850800376599BD698B1961A5E /* MBLEntityModule.h in Headers */, - B79DA90754CBBA0513569A6F5E3C3C00 /* MBLEntityModule+Private.h in Headers */, - C0C33C48226D2F294414E397B700D3F7 /* MBLEulerAngleData.h in Headers */, - 6965BE90DB2A4F28DDC5EE2B31B61433 /* MBLEulerAngleData+Private.h in Headers */, - 54532A80EC7747EB2E21582D91C026DA /* MBLEulerFormat.h in Headers */, - 7ECCE9FCCA33E7264FC83790FFB4783A /* MBLEvent.h in Headers */, - DBC29BC4541E4385BC95E162358E0779 /* MBLEvent+Private.h in Headers */, - 6B2158F34E8AFBF2AF63C529AF6E1662 /* MBLExternalThermistor.h in Headers */, - 71E3FF46E57649D62DAEA5F88D8A4896 /* MBLExternalThermistor0.h in Headers */, - 5CEFF7EB8BCC2687ABB478D0204F5A36 /* MBLExternalThermistor1.h in Headers */, - 226C4C2401451A6BCB171A06ABDC69DA /* MBLFilter.h in Headers */, - E352E7D4C9D3E2A731153221B88921BB /* MBLFilter+Private.h in Headers */, - 05D83FFA467CF5F869AB3108853AA661 /* MBLFirmwareBuild.h in Headers */, - 5C83BE1C9F476163517EA0C0ACBA4482 /* MBLFirmwareUpdateInfo.h in Headers */, - 497D53BB698030F17746C7FB4FD5039F /* MBLFirmwareUpdateManager.h in Headers */, - 607D6C4B48514522D839AECA18D5C01E /* MBLFormat.h in Headers */, - 635314D5BE8A729A2701E5B7B4E88E11 /* MBLGPIO.h in Headers */, - 727EB55637BBA5D63E9C71B19F6574D6 /* MBLGPIO+Private.h in Headers */, - 66FA9D9451995E3D50248954D900A9B9 /* MBLGPIOData.h in Headers */, - 06F7178BDB544DE97F5D1794C8DA06BA /* MBLGPIOPin.h in Headers */, - 20840E7E1F6D316A47C8A6C64DEB3AFB /* MBLGPIOPin+Private.h in Headers */, - E21E851F3D9F8F51D7A868DC560429A8 /* MBLGPIOPinChangeEvent.h in Headers */, - A4A79DFC8B12396BC9400E1D614EF112 /* MBLGravityFormat.h in Headers */, - 0801F55D311EA5344545D6804E5C3402 /* MBLGyro.h in Headers */, - 43DD5997299CE6CABAF398150937871A /* MBLGyro+Private.h in Headers */, - 24387CE4EB22A66598C11C57658EC110 /* MBLGyroBMI160.h in Headers */, - 45D9172EC3A085B300D1D3574E8B1A3C /* MBLGyroBMI160+Private.h in Headers */, - 06BB08C3AFF8E49AF1E2BB80954D2432 /* MBLGyroBMI160AxisReadyEvent.h in Headers */, - 413569643E45773A84A347CD2FC21592 /* MBLGyroBMI160DataReadyEvent.h in Headers */, - 30555802874EDB3C6132B1B31470922B /* MBLGyroBMI160Format.h in Headers */, - E4C649663E1F2050333323689070E9B4 /* MBLGyroBMI160PackedDataReadyEvent.h in Headers */, - 4B91A41B9BCE19D03B6D92A4F6B5BF86 /* MBLGyroData.h in Headers */, - 9471CA8DA9878011E9D44B15F91A4BA0 /* MBLGyroData+Private.h in Headers */, - E1D953B9AADC002F4CB917B32C67967D /* MBLHapticBuzzer.h in Headers */, - E0B99E76EE958678464B38396A04D90A /* MBLHygrometer.h in Headers */, - 8CF605AC994E3AB0AAF7A841C6E235E6 /* MBLHygrometer+Private.h in Headers */, - 8B30EA459330DBE023433AE07240587F /* MBLHygrometerBME280.h in Headers */, - 2B027C37026176ABA5B48E7F0DE2C6DE /* MBLHygrometerBME280PeriodicHumidityEvent.h in Headers */, - 91F3FC606720D6E38438D3AC22E6877B /* MBLI2C.h in Headers */, - C0A90325A2E7C8B558B3B4D7C13BC2B4 /* MBLI2CData.h in Headers */, - 12B5141E9F82B27014FD48968EACF549 /* MBLI2CData+Private.h in Headers */, - AB9EDE885EB28B940082A14083F6CB4C /* MBLiBeacon.h in Headers */, - 97F9C7DCFD0210D0AF29742C1336B914 /* MBLLED.h in Headers */, - DCB43723E364DB6788C3BAF8ED99FC5E /* MBLLED+Private.h in Headers */, - 7B029D89988C9741C1488653964B6C70 /* MBLLogger.h in Headers */, - 020A7B0219E3750F0A6BEA393AC1CFD8 /* MBLLogging.h in Headers */, - 5043CFE6ACCA434053B850AA26C6468A /* MBLLoggingV0.h in Headers */, - C78DD531D7ADDE389D58AC90CD163FFB /* MBLLoggingV1.h in Headers */, - 8ECE7CB345AF9EAD0B6518AD7CDFA11B /* MBLLoggingV2.h in Headers */, - B0CCBA3FA4406129F1F409598E85045D /* MBLMacAddressFormat.h in Headers */, - F3CD6B4A5B51B4CEDAD4D7718A696608 /* MBLMacro.h in Headers */, - FEB46AF0929D4D9D68B98E1D8F7F2ED0 /* MBLMagnetometer.h in Headers */, - C8E49F832BA4CDACBB754F207B889EE6 /* MBLMagnetometer+Private.h in Headers */, - 940A5DAF9BD33DBE9985BFD6807F52BC /* MBLMagnetometerBMM150.h in Headers */, - 9108610EF85A7D346E9726D5DF1A6933 /* MBLMagnetometerBMM150+Private.h in Headers */, - 7165B4A242D1918D7437E3C990225F4A /* MBLMagnetometerBMM150Format.h in Headers */, - 38B840E7146BFA32100316A034CA1AC4 /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.h in Headers */, - ED881C93A86D1B03630F20381EC0CCA5 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.h in Headers */, - CA566D69FF3773754415A22C9A5E9EAF /* MBLMagnetometerData.h in Headers */, - E1FADA244CD8C6C19DCBAB65F95F8A97 /* MBLMagnetometerData+Private.h in Headers */, - 3F74D86D18CFA6D819272FE07F49DC1F /* MBLMechanicalSwitch.h in Headers */, - 68BE1D1D8269258A13805590BA9BFCFC /* MBLMetaWear.h in Headers */, - 9F9C97200E884E5D0E8C6380EB33F10C /* MBLMetaWear+Private.h in Headers */, - 3D6693BBDE954357B923A260F6B25286 /* MBLMetaWearManager.h in Headers */, - 1A4807E59E5219D6D0605E8DD37D7198 /* MBLMetaWearManager+Private.h in Headers */, - 07E77E69832FA381EFE3627F575866FF /* MBLMockPeripheralFactory.h in Headers */, - 99603D6C816D6502154D00E467A409CE /* MBLMockUtils.h in Headers */, - C5DEA8D620EA6295CD81B9E0DC349402 /* MBLModule.h in Headers */, - BC64B743E0E8A66ED93B5609D3325CDF /* MBLModule+Private.h in Headers */, - CF3B9128DBFEB8241563931619B8E7FF /* MBLModuleInfo.h in Headers */, - 6D1F8A96CF6E640CB79EEC7B33645EF6 /* MBLModuleMock.h in Headers */, - DB3AC10325C65DD276844A4DA56C5930 /* MBLMovingAverage.h in Headers */, - 9F53304512F490377492AA1C45139C04 /* MBLNeopixel.h in Headers */, - 81F7AD2B1301FFB9E0C7FDD58F49B306 /* MBLNeopixel+Private.h in Headers */, - 8DE2656207A57205A8096E85DC879A44 /* MBLNeopixelStrand.h in Headers */, - 984F476A550E339070B3ADD7C4C86B36 /* MBLNeopixelStrand+Private.h in Headers */, - F0DD090C2F438F7D454504613A8AC5B2 /* MBLNonVolatileState.h in Headers */, - F135C9FE51E500398FCAF3183359338C /* MBLNumericData.h in Headers */, - 1F3AE218EA2C44267A07C339C5E9D27A /* MBLNumericData+Private.h in Headers */, - 7FABE86421E53EC44D62B7CAB80BED09 /* MBLNumericFormatter.h in Headers */, - 69E48770693B48B615CE85C5C5335970 /* MBLOnDieTemperature0.h in Headers */, - 68D0171DA92D9EFEC1E43BF9B5ABC35B /* MBLOrientationData.h in Headers */, - 3F5B74E52A297C4E329E326B84636A4D /* MBLOrientationData+Private.h in Headers */, - 7CC91D5E3718E1E4C24D4C2D8D624568 /* MBLPhotometer.h in Headers */, - 3B127F5F000ADF67A4FE001045BDAA2F /* MBLPhotometer+Private.h in Headers */, - 9B246E73DAF18E3BCE7B1F75D3CBEBAC /* MBLPhotometerTCS3472.h in Headers */, - 7190F5456EAE7F0CEFE8427977F4CE73 /* MBLPhotometerTCS3472Format.h in Headers */, - 5FAF9A60E2E7DF6459B806B2EA13A02F /* MBLProximity.h in Headers */, - FEBCCC4E19AA5490CDF85FCB85AF2EF0 /* MBLProximity+Private.h in Headers */, - F34EDB8535E392FFB6CA369128586840 /* MBLProximityTSL2671.h in Headers */, - 860E77BEA6D076A8D37A3C81DBE4E02E /* MBLQuaternionData.h in Headers */, - 27355E532094E863B6034A77D65040C5 /* MBLQuaternionData+Private.h in Headers */, - F6B763D2AEAF6E413FD4D997E396CF2D /* MBLQuaternionFormat.h in Headers */, - BB9BAE65895E2A87EF650E43306262A4 /* MBLRegister.h in Headers */, - 868DE34BBEC92B602990B89F809BBBB0 /* MBLRegister+Private.h in Headers */, - 490107A856F476787977D8E183EEC0D2 /* MBLRGBData.h in Headers */, - A2D30CF69D06FCBDD0E0C56057855FA3 /* MBLRGBData+Private.h in Headers */, - 644C0E9C4C1C4E43BB139B07AB4AF614 /* MBLRMSAccelerometerData.h in Headers */, - 61ACDE06EBBB628AF0C3028B938ECCB8 /* MBLRMSAccelerometerData+Private.h in Headers */, - C6B218A24D2655E817143B75F2AE6239 /* MBLSensorFusion.h in Headers */, - FA522FEAA890D4F8BB7ABBE5ECC5EACB /* MBLSensorFusion+Private.h in Headers */, - 74024E47E558B9F4F86C0276248BF68C /* MBLSerial.h in Headers */, - 532AD22B6AB432104B999955188A7041 /* MBLSerial+Private.h in Headers */, - 81A2D1DF71EE274A6DC7447C57FF9A4C /* MBLSettings.h in Headers */, - F61DB9A5C99B33D0A9BADE7858F81EBD /* MBLSettings+Private.h in Headers */, - C33C9FF48D09DAC9817823DD802DF6EE /* MBLSPIData.h in Headers */, - 1F332C51AB92D2E9E46BB0D5CBEE2E80 /* MBLSPIData+Private.h in Headers */, - 839D9CC4E54739EB4EFFC5B81A2A6D2E /* MBLStringData.h in Headers */, - 0147A16532A6FC4DFD7956C09989FB5D /* MBLStringData+Private.h in Headers */, - E4D7303B5F927BB34DB1DE592239C6A8 /* MBLTemperature.h in Headers */, - 9BD4469FACF1754518D884524C7FC482 /* MBLTemperature+Private.h in Headers */, - 3689B88517E22DD7FE2301D599CFE214 /* MBLTemperatureV0.h in Headers */, - C36D7D51D5F496C1FCA1968B8DAFBAB2 /* MBLTemperatureV1.h in Headers */, - 7578004323F87F1A9D1F2A57A01772C5 /* MBLTestDebug.h in Headers */, - 98ACBC08142F99B0FE54A234B7EA8344 /* MBLTimer.h in Headers */, - 6899FB350AA150209056CEDBB36F1E6E /* MBLTimer+Private.h in Headers */, - 99213BC3E73DB02EB2D188F075853AD6 /* MBLTimerEvent.h in Headers */, - FA7A067DA6BF6A3A00E0E0FB148319EF /* MBLTimerEvent+Private.h in Headers */, - 68433728E8193F655A3854DF8AD5C76A /* MBLTriggeredRead.h in Headers */, - 8F0CEF19DCC1EBC96C119EBB51F0E69C /* MetaWear.h in Headers */, - 10B1604C0D6BA26700F79DBDB92F6EE7 /* MetaWearPrivate-umbrella.h in Headers */, - C5CE3E1392D6B8B6CBC812E08A461F4A /* mma8452q.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 5D82C29ACD851E6EA219B34A73C961F5 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -2145,55 +926,46 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5F5935905876BD17CA38B91C2CD3ADA5 /* Headers */ = { + 72C07810A5CBA2C8C4F74E325804CD5C /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 63A94CE8B3BA5E885E9B60D64B51C2CD /* Pods-MusicalCaneGame-umbrella.h in Headers */, + D0DD5463F075AA2300AA953722562725 /* Bolts-Swift-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - C27871A6E993A6F877B5389D4FD4EF9A /* Headers */ = { + A750A85D1B0555AD20DA9BA82B4EB84B /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 77563A5F471F5C1F6B3B40FFCA138892 /* PRTween.h in Headers */, - AE509515FB5C6503228AA70CC68FE759 /* PRTween-umbrella.h in Headers */, - 8EAC37DD9A8F09AFAE51AAC1DB22B5B7 /* PRTweenTimingFunctions.h in Headers */, + 69BDA1DCEF0ABC445229657CBB5F7674 /* Pods-MusicalCaneGame-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - DC067DAACBF9310E66CB1EC696C9DD8A /* Headers */ = { + AA80FAC5F3845CD4B382B6354949BCF3 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 3C2241BAABC2201EA6AFC9A832828D37 /* BFCancellationToken.h in Headers */, - 4CA9B1A258191CF5DEB8DF9D446656D9 /* BFCancellationTokenRegistration.h in Headers */, - EE5C34446DAACC83AEFBF004F31D535E /* BFCancellationTokenSource.h in Headers */, - 373FF98F6ED4C09EBBBDC23A104D8021 /* BFExecutor.h in Headers */, - 787102F95ED2B50406F8C0BC3BCD78BC /* BFTask.h in Headers */, - D1DCAEB4F311D177D6C27826B82BDB95 /* BFTask+Exceptions.h in Headers */, - BA81DFE0ECEC3454B415644491BB9559 /* BFTaskCompletionSource.h in Headers */, - 89E907B9708FF15598D1A117D60BED53 /* Bolts.h in Headers */, - 41D3F2967EE6E602190072C480F327EE /* Bolts-umbrella.h in Headers */, + 82F97C08FD25705A24C869FE3BB0D4F0 /* MetaWear-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - DD214513A4390595BE08F1663FCE1BBE /* Headers */ = { + C27871A6E993A6F877B5389D4FD4EF9A /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 56C52024171B7188E3144EF14E8F832B /* StaticDataTableViewController.h in Headers */, - 96ED90E71125694BFDCC554BB5F68CC0 /* StaticDataTableViewController-umbrella.h in Headers */, + 77563A5F471F5C1F6B3B40FFCA138892 /* PRTween.h in Headers */, + AE509515FB5C6503228AA70CC68FE759 /* PRTween-umbrella.h in Headers */, + 8EAC37DD9A8F09AFAE51AAC1DB22B5B7 /* PRTweenTimingFunctions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - FD3579C671161332B2B49EC3A0709B1D /* Headers */ = { + DD214513A4390595BE08F1663FCE1BBE /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 7E2B04696BAEDDCCB43948F773D855A8 /* FastCoder.h in Headers */, - FCB139CFF9D146093A70F4281888B15D /* FastCoding-umbrella.h in Headers */, + 56C52024171B7188E3144EF14E8F832B /* StaticDataTableViewController.h in Headers */, + 96ED90E71125694BFDCC554BB5F68CC0 /* StaticDataTableViewController-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2202,84 +974,64 @@ /* Begin PBXNativeTarget section */ 0602CA84D1340CD4BEDF2B2DBBD78E1C /* Pods-MusicalCaneGame */ = { isa = PBXNativeTarget; - buildConfigurationList = A48BFDDB7FA0FDDFBE8F2C4A5A84883F /* Build configuration list for PBXNativeTarget "Pods-MusicalCaneGame" */; + buildConfigurationList = 12DB945DF6C6F5198BAEAC2F2D8C2F12 /* Build configuration list for PBXNativeTarget "Pods-MusicalCaneGame" */; buildPhases = ( - 5F5935905876BD17CA38B91C2CD3ADA5 /* Headers */, - B40E9DC0F2264372CD27EE674F768799 /* Sources */, - D8739B7FA86987058BB9003084FC7234 /* Frameworks */, - 9875D3D17AECE4A4BCE2351143823D14 /* Resources */, + A750A85D1B0555AD20DA9BA82B4EB84B /* Headers */, + 3A3F73B011E54B1329BBCFD3804079B4 /* Sources */, + 646C45A726428B6E68D423DD13C842C7 /* Frameworks */, + 10C716ECDB32CA2E8C43216C3A8891D0 /* Resources */, ); buildRules = ( ); dependencies = ( - 7D603B44299285C250A86A033EA4D91C /* PBXTargetDependency */, - E2ADB3953728F3E835E0BF93ACA182E8 /* PBXTargetDependency */, - 2D047A425F7112B541ED7A844B85406F /* PBXTargetDependency */, - 52D55436D59EA269A67CD12FCD9E9395 /* PBXTargetDependency */, - 9B139D32ADF4ADEC9AFBC4F35C58EBC0 /* PBXTargetDependency */, - 88F81D67FDC9A272DD7CF0DABA7A0D8D /* PBXTargetDependency */, - 61D6476397F039C319662134028750FB /* PBXTargetDependency */, - 25D59D8872E28BD5F8062BC86259C9FA /* PBXTargetDependency */, + FC6D394FA60F863AAE5A8846C37F72B1 /* PBXTargetDependency */, + C513F7F2B5456216659494DD1B833389 /* PBXTargetDependency */, + 6AE73402F576A13695BCDAC7C8A2330B /* PBXTargetDependency */, + 5A7BD700175A01ACC0A85A3A35B7383D /* PBXTargetDependency */, + 267A5824DDA953BC85B27209E3DEDA57 /* PBXTargetDependency */, + 16CB94919108AE8EECABC7432ED09C8F /* PBXTargetDependency */, + B0A71D24ADECFD8DC49CD98816919705 /* PBXTargetDependency */, ); name = "Pods-MusicalCaneGame"; productName = Pods_MusicalCaneGame; productReference = B6B2138B534DA2D64E869EF442A8C7D1 /* Pods_MusicalCaneGame.framework */; productType = "com.apple.product-type.framework"; }; - 3F2C1776D90B62B156DB52C41A5C419C /* SQLite.swift */ = { + 3E8BB3BAFA6478784A9A7DD76C8A1F3C /* MetaWear */ = { isa = PBXNativeTarget; - buildConfigurationList = 397A93C7BC4A46621D30B1A9F21A5A12 /* Build configuration list for PBXNativeTarget "SQLite.swift" */; + buildConfigurationList = 753A955E3C890042144DB875D1ED351A /* Build configuration list for PBXNativeTarget "MetaWear" */; buildPhases = ( - 316B33EB7B633BE4100F70E404C10B00 /* Headers */, - 71308DD58F2FD16A6C619B8FE6B943FB /* Sources */, - 4F531717FFC44CFD566D66CC66316B8B /* Frameworks */, - AC7EC90528DCCA84FF00EE15CEA4B6AB /* Resources */, + AA80FAC5F3845CD4B382B6354949BCF3 /* Headers */, + C732AC4B04BA52C384FF18EF091E45E0 /* Sources */, + 3DD73F8FFEB15B96AB33B8A17DAB8123 /* Frameworks */, + A26F74FF8BD409F8E32028478B803172 /* Resources */, ); buildRules = ( ); dependencies = ( + 3E317370606D51A4E332AB0CC85802DC /* PBXTargetDependency */, ); - name = SQLite.swift; - productName = SQLite; - productReference = F5FA45A44C42CC2CA3A324A3E914CE19 /* SQLite.framework */; - productType = "com.apple.product-type.framework"; - }; - 42465A188431886AB035275F049824D3 /* Bolts */ = { - isa = PBXNativeTarget; - buildConfigurationList = EFB970C8C306436F33E2A0084A838F7D /* Build configuration list for PBXNativeTarget "Bolts" */; - buildPhases = ( - DC067DAACBF9310E66CB1EC696C9DD8A /* Headers */, - 33E4281836D08C622F0139626C030FF4 /* Sources */, - F8016C61CF40B45EA8222E137657E5F9 /* Frameworks */, - ED7E41CCB20C78A6C8B5F35C01AAE1FF /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Bolts; - productName = Bolts; - productReference = F84B331B5D6AAF1548DD1BB004AE5C2A /* Bolts.framework */; + name = MetaWear; + productName = MetaWear; + productReference = 7DF415FCE4EC0E6B83191E69BD55A61F /* MetaWear.framework */; productType = "com.apple.product-type.framework"; }; - 5F93A6259A037F8247AD055CC3E8F98E /* MetaWearPrivate */ = { + 3F2C1776D90B62B156DB52C41A5C419C /* SQLite.swift */ = { isa = PBXNativeTarget; - buildConfigurationList = C64E84974E44FEF637DB6271C8FDF930 /* Build configuration list for PBXNativeTarget "MetaWearPrivate" */; + buildConfigurationList = 397A93C7BC4A46621D30B1A9F21A5A12 /* Build configuration list for PBXNativeTarget "SQLite.swift" */; buildPhases = ( - 47ADB6E85546F0E00B11725E4D5A1858 /* Headers */, - B741F586BDBF4D4AD93DA0363471A951 /* Sources */, - A38EDC82DFFEEE2A2C06452BCAF08334 /* Frameworks */, - 8C323E1BA594D9FDA3A410FF36CA4F3B /* Resources */, + 316B33EB7B633BE4100F70E404C10B00 /* Headers */, + 71308DD58F2FD16A6C619B8FE6B943FB /* Sources */, + 4F531717FFC44CFD566D66CC66316B8B /* Frameworks */, + AC7EC90528DCCA84FF00EE15CEA4B6AB /* Resources */, ); buildRules = ( ); dependencies = ( - 62A8FEEBE8C797886DD868DBC158E50A /* PBXTargetDependency */, - 72C660A1C738678A6D3B32E48C8B9F91 /* PBXTargetDependency */, ); - name = MetaWearPrivate; - productName = MetaWear; - productReference = 3AB44C67614744596C398BB3B0F6913A /* MetaWear.framework */; + name = SQLite.swift; + productName = SQLite; + productReference = F5FA45A44C42CC2CA3A324A3E914CE19 /* SQLite.framework */; productType = "com.apple.product-type.framework"; }; 7121634C8DA4533EB626AEE3C697BFAB /* StaticDataTableViewController */ = { @@ -2336,24 +1088,6 @@ productReference = 8B8FAB0D627B17EDE1366984278705D9 /* MBProgressHUD.framework */; productType = "com.apple.product-type.framework"; }; - 8CB1610D02CF2E1138DAFFDA5722B39A /* FastCoding */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1AD87D09F1FD2A9FE3A07101B961DED4 /* Build configuration list for PBXNativeTarget "FastCoding" */; - buildPhases = ( - FD3579C671161332B2B49EC3A0709B1D /* Headers */, - 359F3B567F47ACDABE8B5B76F3ECB0CD /* Sources */, - 3427D5FAF7238C4B5B07F26129576E7A /* Frameworks */, - CF2B1CABCDEDFD463C17C0FFF9F33166 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = FastCoding; - productName = FastCoding; - productReference = 7CDA43646778C7DF1FF0FA8624D6F105 /* FastCoding.framework */; - productType = "com.apple.product-type.framework"; - }; 9A9A6DFBF33C0809BD9B32C8C8B776E8 /* FlexColorPicker */ = { isa = PBXNativeTarget; buildConfigurationList = 338E3A98A137AD8DAD22F0E2D4CF379A /* Build configuration list for PBXNativeTarget "FlexColorPicker" */; @@ -2372,6 +1106,24 @@ productReference = 741F9D3943FF7542B04631B29216270F /* FlexColorPicker.framework */; productType = "com.apple.product-type.framework"; }; + BA1CEDB360B77644C934EAD86B37FCB5 /* Bolts-Swift */ = { + isa = PBXNativeTarget; + buildConfigurationList = C48222D97D3730ADFA867FB3A54056D0 /* Build configuration list for PBXNativeTarget "Bolts-Swift" */; + buildPhases = ( + 72C07810A5CBA2C8C4F74E325804CD5C /* Headers */, + 2E5174D8ABD0F86071CCA0A8D8389465 /* Sources */, + 027D1E80DE0AD8115B0EF3B90C9DAB38 /* Frameworks */, + 41A719F7AA99C290E0862BC65E63E79C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Bolts-Swift"; + productName = BoltsSwift; + productReference = 1579A0986D70C32D7BED1A855C31EF4B /* BoltsSwift.framework */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -2382,7 +1134,7 @@ LastUpgradeCheck = 1500; }; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; - compatibilityVersion = "Xcode 10.0"; + compatibilityVersion = "Xcode 12.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -2390,15 +1142,14 @@ en, ); mainGroup = CF1408CF629C7361332E53B88F7BD30C; - productRefGroup = 53F2503F1BF9315EAC94288E0106B8F3 /* Products */; + productRefGroup = 79D8BC9D6E476A06F5C3ABBE5EFB4F34 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 42465A188431886AB035275F049824D3 /* Bolts */, - 8CB1610D02CF2E1138DAFFDA5722B39A /* FastCoding */, + BA1CEDB360B77644C934EAD86B37FCB5 /* Bolts-Swift */, 9A9A6DFBF33C0809BD9B32C8C8B776E8 /* FlexColorPicker */, 82B0A41D3031FF27D78E17B0A9A46FB0 /* MBProgressHUD */, - 5F93A6259A037F8247AD055CC3E8F98E /* MetaWearPrivate */, + 3E8BB3BAFA6478784A9A7DD76C8A1F3C /* MetaWear */, 0602CA84D1340CD4BEDF2B2DBBD78E1C /* Pods-MusicalCaneGame */, 75CA230D0637BEBCCBE6371A0E6B5B6B /* PRTween */, 3F2C1776D90B62B156DB52C41A5C419C /* SQLite.swift */, @@ -2408,42 +1159,42 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 3E1E6BF4D269BCB313953819F68C2CD9 /* Resources */ = { + 10C716ECDB32CA2E8C43216C3A8891D0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 8C323E1BA594D9FDA3A410FF36CA4F3B /* Resources */ = { + 3E1E6BF4D269BCB313953819F68C2CD9 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 9875D3D17AECE4A4BCE2351143823D14 /* Resources */ = { + 41A719F7AA99C290E0862BC65E63E79C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - AC7EC90528DCCA84FF00EE15CEA4B6AB /* Resources */ = { + A26F74FF8BD409F8E32028478B803172 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - C0E0F7D28F4D633128D0F53BEAE34D3D /* Resources */ = { + AC7EC90528DCCA84FF00EE15CEA4B6AB /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - CF2B1CABCDEDFD463C17C0FFF9F33166 /* Resources */ = { + C0E0F7D28F4D633128D0F53BEAE34D3D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -2464,29 +1215,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - ED7E41CCB20C78A6C8B5F35C01AAE1FF /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 33E4281836D08C622F0139626C030FF4 /* Sources */ = { + 2E5174D8ABD0F86071CCA0A8D8389465 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5793C02AA8B4CCC0D886165799B5E406 /* BFCancellationToken.m in Sources */, - E20FB97E7825A9F5BB5B2E35966F9459 /* BFCancellationTokenRegistration.m in Sources */, - 7D6085C3E8DFCE88A4B15814DC64F268 /* BFCancellationTokenSource.m in Sources */, - 8BA06EE3F00F3EB4918CAD7306D8CEF4 /* BFExecutor.m in Sources */, - D24328ED34ACC9B1543D1B9A3A8A4869 /* BFTask.m in Sources */, - 3B4FDE53274DA00790C4262C8B3BEA98 /* BFTask+Exceptions.m in Sources */, - 112A40C3F3E10E913219C547E2278636 /* BFTaskCompletionSource.m in Sources */, - 87D208C7E5C207583A0AFD7A3CBD22EF /* Bolts.m in Sources */, - 75BF42D982E4A787DFC938A265C6DBE2 /* Bolts-dummy.m in Sources */, + 23AB401EA2DC9BAA435B033E704A9406 /* Bolts-Swift-dummy.m in Sources */, + 95E46181D8FC4AC4C20F177220805D59 /* Errors.swift in Sources */, + 5CC566CCC0055546155D57902D10B574 /* Executor.swift in Sources */, + 7AEF07B308BAC5CF75B0DBCC591DDAAE /* Task.swift in Sources */, + 57E4358DF5A349E14418DDAD0619B3E9 /* Task+ContinueWith.swift in Sources */, + 1344095A86FEF755B39DE3700F727A5F /* Task+Delay.swift in Sources */, + A9ECF13DC52C6742BFFCA3112B62B975 /* Task+WhenAll.swift in Sources */, + 408E6D25175C92C8DF19EC2AD52B0473 /* Task+WhenAny.swift in Sources */, + 636B54447CEE73B5F2CC4B0472D35CA4 /* TaskCompletionSource.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2532,12 +1276,11 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 359F3B567F47ACDABE8B5B76F3ECB0CD /* Sources */ = { + 3A3F73B011E54B1329BBCFD3804079B4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - EF839C7C1F3D490E0D803222BBECA6AD /* FastCoder.m in Sources */, - 6FDD6413C4975D6B93009C7F86E9FD33 /* FastCoding-dummy.m in Sources */, + E9D69372A158F024635C786160B2D719 /* Pods-MusicalCaneGame-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2599,240 +1342,128 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - B40E9DC0F2264372CD27EE674F768799 /* Sources */ = { + C732AC4B04BA52C384FF18EF091E45E0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E2890E4DEF6E67952436180636C81064 /* Pods-MusicalCaneGame-dummy.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B741F586BDBF4D4AD93DA0363471A951 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 666E5C596955D4F4587873DD4ABF98F3 /* BFTask+MBLExtensions.m in Sources */, - 878250824396973CC3136EB252DA7808 /* BFTask+MBLPrivate.m in Sources */, - DFB4BE1BDE7704075922033B431F3660 /* MBLAccelerometer.m in Sources */, - 0F1BDD331C0BF9B6556C473CFF9C9BE2 /* MBLAccelerometerAxisReadyEvent.m in Sources */, - B0A17D93DEC37FBFEE2DD5870951785D /* MBLAccelerometerBMA255.m in Sources */, - 52ADFFADF505CD10EAC7505DCEAE2C0A /* MBLAccelerometerBMA255MotionEvent.m in Sources */, - F84C73866CEE373D62DF36A6AB652C55 /* MBLAccelerometerBMI160.m in Sources */, - D212A71052A618EA16A6EE2902DB449E /* MBLAccelerometerBMI160MotionEvent.m in Sources */, - F8CBBEB30F91DD5D67775AE2BB500709 /* MBLAccelerometerBMI160StepEvent.m in Sources */, - EF7C980431AF65A6BA0E612F4D92A4AD /* MBLAccelerometerBosch.m in Sources */, - A2F14B12F347667B99ADE221F3C55C10 /* MBLAccelerometerBoschAxisReadyEvent.m in Sources */, - B9B8A4F1B99AE2827D8F87354994E16F /* MBLAccelerometerBoschDataReadyEvent.m in Sources */, - 414EEDDA388C02134F293D3A237BB09E /* MBLAccelerometerBoschFlatData.m in Sources */, - 2FF483BFBDD47B9E1E507E3CCD6E0F4D /* MBLAccelerometerBoschFlatEvent.m in Sources */, - 1639DF4A53A68B459C2EA18C387A6A54 /* MBLAccelerometerBoschFlatFormat.m in Sources */, - 1B007F916C7DC8CB13580EFAE4F7D6AF /* MBLAccelerometerBoschFormat.m in Sources */, - 484358B01F3C24B4E0CF024F8D40AF8B /* MBLAccelerometerBoschLowOrHighGEvent.m in Sources */, - B299707DAB665E5C20B8A1A10C4BD342 /* MBLAccelerometerBoschOrientationEvent.m in Sources */, - 6DF299FE058A9CE2D0970D006D2453D2 /* MBLAccelerometerBoschOrientationFormat.m in Sources */, - E60FF3CD3C3032931BF9D35AE8EE18FC /* MBLAccelerometerBoschPackedDataReadyEvent.m in Sources */, - 6DCC7FF7294F8D0F2B15DC2298C05835 /* MBLAccelerometerBoschRMSFormat.m in Sources */, - CF0447DDC959205BCFB42B4EB655645B /* MBLAccelerometerBoschTapEvent.m in Sources */, - E77FAE2B61E1FC76DDF18C5FF69EB52F /* MBLAccelerometerData.m in Sources */, - C58610A0A7F45490156BD2A2B485F965 /* MBLAccelerometerDataReadyEvent.m in Sources */, - DE24ACA4B2C8E66BE111A04B8949425C /* MBLAccelerometerFreeFallEvent.m in Sources */, - B44D91A49063DD48F3EAAF4AFEEC8783 /* MBLAccelerometerMMA8452Q.m in Sources */, - 6A1D646998914294C2A425353C799D01 /* MBLAccelerometerMMA8452QFormat.m in Sources */, - 583410DAC575A9BB1C11E658752463EF /* MBLAccelerometerMMA8452QOrientationFormat.m in Sources */, - 42AD0F3D9A465A754CA101206B10C5B3 /* MBLAccelerometerMMA8452QRMSFormat.m in Sources */, - 87F9923DE5AA22BA7FF6EC67CF184D91 /* MBLAccelerometerOrientationEvent.m in Sources */, - B59CF6F64C1DA915D1E780479BACFFDE /* MBLAccelerometerPackedDataReadyEvent.m in Sources */, - D6C8986CBE92ABAE5156BBF2D344336F /* MBLAccelerometerShakeEvent.m in Sources */, - 6816B32CDE508E3A8718BDFF40DAC085 /* MBLAccelerometerTapEvent.m in Sources */, - DF1D172F1BE8BBE268AD9ED807E78970 /* MBLAmbientLight.m in Sources */, - AE970A3D760E50E6DEC90A85713B9CCC /* MBLAmbientLightLTR329.m in Sources */, - 3E950E56661FACDAB6426E793300F06C /* MBLAnalytics.m in Sources */, - 234BE91335646A9ADF3340A2F8207CDF /* MBLANCS.m in Sources */, - B59AD511EECEBAE1A6896FFAC0F956CD /* MBLANCSEventData.m in Sources */, - D7A26AD0A8698181B4CABEF0CC48168C /* MBLAnonymousEvent.m in Sources */, - 4B292CE74CB55C12F36BB25AC2CE00B7 /* MBLBarometer.m in Sources */, - 6658CA9DED4180C6E730A30CB5F2C845 /* MBLBarometerBME280.m in Sources */, - 680A98138C269CA0E7A7FEC58978C2A9 /* MBLBarometerBMP280.m in Sources */, - B16A40603362F6B7A6252136C019AF07 /* MBLBarometerBosch.m in Sources */, - 0CA4B372C03A35AAFF0C800916876278 /* MBLBarometerBoschPeriodicAltitudeEvent.m in Sources */, - 1D03237EF9F22AFEAAEECAF8853E5FAB /* MBLBarometerBoschPeriodicPressureEvent.m in Sources */, - 65238E3396193C34F7CC14E6FCF5F846 /* MBLBitmaskEvent.m in Sources */, - 5E919B07455AD8D8CB6C2F57917580F2 /* MBLBluetoothCentralMock.m in Sources */, - 815A632D16FECA82FC1D41D45BB5D1D1 /* MBLBluetoothPeripheralMock.m in Sources */, - 14DBF52DB826D0A1391DDA0EEF1C8AED /* MBLCategoryLoader.m in Sources */, - A1C9242CA4B22CB221EFEDF026EF6C5B /* MBLCommand.m in Sources */, - E52F5B8CBD021B21220129C3597146D6 /* MBLConductance.m in Sources */, - 9455D90CA249F092044C5265B0E37916 /* MBLConductanceData.m in Sources */, - AB59BEE6A9C358955FC2F2569C641CF0 /* MBLConstants.m in Sources */, - 5BC0A54144FE09136D30DC97003FB7BE /* MBLConversion.m in Sources */, - 8892EF77B05789AD6F6BC18D90AB8585 /* MBLCorrectedFormat.m in Sources */, - 7497AC4ECC997A66B500A88BC0B7818F /* MBLData.m in Sources */, - 71416B3D101EB7B008EBFFEDD7829035 /* MBLDataProcessor.m in Sources */, - 5E7E728EF90BDE8D85E46993DFD2A041 /* MBLDataSample.m in Sources */, - DD96B7D6D05C6CD7F3C68DA5190965AD /* MBLDataSwitch.m in Sources */, - 11C9627A459E29CC6BA76AB490BABF44 /* MBLDependentData.m in Sources */, - C75EC2FDE5619D3F7393E4A5B4D4DAF6 /* MBLDeviceInfo.m in Sources */, - 742F56778C738333597F6A15742614EE /* MBLDeviceLookup.m in Sources */, - D1285DA4503F99A14C1CECBE71E0AF03 /* MBLDispatchQueue.m in Sources */, - 8068499A3E8EF7B85DA9E67272CD44CD /* MBLDownloadOnlyEvent.m in Sources */, - 7B81156F3AFD5D3B695E13405F508DF1 /* MBLEntityEvent.m in Sources */, - 49BC4B1FB2948A43E35EABB82D5E4A24 /* MBLEntityModule.m in Sources */, - 15EF18D5B21AC5FF492796700C5B1324 /* MBLEulerAngleData.m in Sources */, - 5FE7A063E370709D0B60DA0BDDE963E3 /* MBLEulerFormat.m in Sources */, - D007F5D7DF6E5D1976DAE4395DBA71D6 /* MBLEvent.m in Sources */, - 82512AE61AB74A900DD786CDB9494594 /* MBLExternalThermistor.m in Sources */, - 32FF9EF7262310025BC6C8A41046122F /* MBLExternalThermistor0.m in Sources */, - 9AB1CF400245D7B0CB2901240D0D8A47 /* MBLExternalThermistor1.m in Sources */, - A880766B4EEF078F97BA8E3FF5BDC6B0 /* MBLFilter.m in Sources */, - A26CA6C72D232E8BA4B61356584B56E3 /* MBLFirmwareBuild.m in Sources */, - 0A1D9145798728AAC724FED0C2C93556 /* MBLFirmwareUpdateInfo.m in Sources */, - CAD31E80D4FA4D955FC986A4B8B7E68A /* MBLFirmwareUpdateManager.m in Sources */, - AEF0B65B1B2CD43D2F74C2AF8909FF0D /* MBLFormat.m in Sources */, - 0740676C2F5E1483FC4D07D8C4F8BB98 /* MBLGPIO.m in Sources */, - 94394FC4BDE915844BC96B5FBD367B48 /* MBLGPIOData.m in Sources */, - 2D9C366A0248B39C56B888892BC52EB2 /* MBLGPIOPin.m in Sources */, - 19121B1C97200A025ECAED7407913066 /* MBLGPIOPinChangeEvent.m in Sources */, - 6CD6A99F7035670F8297D8122D90102A /* MBLGravityFormat.m in Sources */, - 05CD19DF403FF52E7CE83801B902DEA2 /* MBLGyro.m in Sources */, - F500F62E9EA41D3BF7760442DD8DAD93 /* MBLGyroBMI160.m in Sources */, - AEA04AFE9100BC69D24A526F9A22CC74 /* MBLGyroBMI160AxisReadyEvent.m in Sources */, - 1B4EEDA4C33178BE372479CED54F4C99 /* MBLGyroBMI160DataReadyEvent.m in Sources */, - E30E3081D2C9E72DDB1C1DC7573FE3BD /* MBLGyroBMI160Format.m in Sources */, - 7966CBED14BE4CDB99874F067FA03BAC /* MBLGyroBMI160PackedDataReadyEvent.m in Sources */, - 4A7A63984642CA0EBCFE8C43F8765D7E /* MBLGyroData.m in Sources */, - 2794F4AB396F19BB731D0F584E973C1A /* MBLHapticBuzzer.m in Sources */, - D434753461729257C4F2C0E765F95955 /* MBLHygrometer.m in Sources */, - 01BCA5FA1B77BF8E96CC28900AB0D77E /* MBLHygrometerBME280.m in Sources */, - 009F84889A3394E6EEA5694403D14C91 /* MBLHygrometerBME280PeriodicHumidityEvent.m in Sources */, - 3278B4E93ACF924EDF92EBD6AE9D2FDC /* MBLI2C.m in Sources */, - 0B41E44FB11C5A3D15B89E42C9CEE1A2 /* MBLI2CData.m in Sources */, - 15F05EF2113378020428917620F96FF8 /* MBLiBeacon.m in Sources */, - 1009D17A0D618C526011C9AA19F5F8F2 /* MBLLED.m in Sources */, - F071B79A43AF6FCFDB0BEFBD80DF0662 /* MBLLogger.m in Sources */, - 391C8178D39D54002F22D51ACC011F7D /* MBLLogging.m in Sources */, - 4D933D264135A38C46269F0B1ADE267C /* MBLLoggingV0.m in Sources */, - 248638FE576616C9ED1D73AC09D03130 /* MBLLoggingV1.m in Sources */, - A8679588CD4819BB74A49D2006658252 /* MBLLoggingV2.m in Sources */, - 5BB334E271C56FAB07D551A09A1C7A35 /* MBLMacAddressFormat.m in Sources */, - A25241523D536543ECD771590FBA3FE3 /* MBLMacro.m in Sources */, - 3418D0C7503FF9243E8BB4CCBD972DE6 /* MBLMagnetometer.m in Sources */, - 99042FD33B155F9606CB60A9D39A0F2D /* MBLMagnetometerBMM150.m in Sources */, - 95F577F0286BE4F7FA035EFCE6262A0B /* MBLMagnetometerBMM150Format.m in Sources */, - 3C607D3FE99007F2B8314642499E338D /* MBLMagnetometerBMM150PackedPeriodicMagneticFieldEvent.m in Sources */, - 93ABF8DBAE90FF09D36CC57F9BCFEF88 /* MBLMagnetometerBMM150PeriodicMagneticFieldEvent.m in Sources */, - 111811351D51010901E4B4B8CD1633DA /* MBLMagnetometerData.m in Sources */, - 0BB895E77A96C2676EF5F978B3A230E0 /* MBLMechanicalSwitch.m in Sources */, - 5B47010C4D6B466C25D14893C7CF13DC /* MBLMetaWear.m in Sources */, - 34F8756D7BC88420992B078B9E96E5CB /* MBLMetaWearManager.m in Sources */, - 5F83A759FD27D04CD4B13BDAF9222F1A /* MBLMockPeripheralFactory.m in Sources */, - D31047011224F20FFD53626316AA8FF8 /* MBLMockUtils.m in Sources */, - E5CAA737AE8493EB95A4DB3EDDA9B33E /* MBLModule.m in Sources */, - 97C0540DFD01F6C1485AD0E014821846 /* MBLModuleInfo.m in Sources */, - EF12270B12F496C08630137D7B227072 /* MBLModuleMock.m in Sources */, - FB078FCB95EF6D4F5F6B063F953E40ED /* MBLMovingAverage.m in Sources */, - A53B216BEF75D7D7D35FF44476620BD5 /* MBLNeopixel.m in Sources */, - 0F334002FACD61A79A23D65C4986FC59 /* MBLNeopixelStrand.m in Sources */, - 112B91D60A3D6D2F015A40E20CCF42E6 /* MBLNonVolatileState.m in Sources */, - 310AE1E2E5EE650ED3EC90ABE54482D3 /* MBLNumericData.m in Sources */, - D255A7BE82C7FDFF215DA9BC9E7D12EA /* MBLNumericFormatter.m in Sources */, - 67CDFE07449FC2151D6CE314BDD143E7 /* MBLOnDieTemperature0.m in Sources */, - B64014FFD36F38A0A273A5A065FE7F15 /* MBLOrientationData.m in Sources */, - 8F93A34C71BC9E0DAB753F1989EA7421 /* MBLPhotometer.m in Sources */, - 73BA62FB8D159A8A88B4263331AEC2E2 /* MBLPhotometerTCS3472.m in Sources */, - 02D0A4DFD38E7F2C645FEEC9207BB60E /* MBLPhotometerTCS3472Format.m in Sources */, - EC15485522F94A0B4F7BD64A8592BE82 /* MBLProximity.m in Sources */, - 989F8569D8A349FF81DBF82E78BF19DE /* MBLProximityTSL2671.m in Sources */, - F7C5C28ADE72BB800E9E39305D0F4E55 /* MBLQuaternionData.m in Sources */, - E635AFF0EA9CF2A025035B1743C4AFE9 /* MBLQuaternionFormat.m in Sources */, - A6CB154A32BC7042285BB8C97FA9E5F0 /* MBLRegister.m in Sources */, - 164808D1E9C4B86AB4D4FA6FDD4EF52A /* MBLRGBData.m in Sources */, - ADE7562DAC780E8A80885053A6053212 /* MBLRMSAccelerometerData.m in Sources */, - 45C09373E5F1AFAEA177220C43931989 /* MBLSensorFusion.m in Sources */, - 0D474A495D7CF25B30ECAB82AB39836F /* MBLSerial.m in Sources */, - E5E70C681E75372DA36E22210441B9E3 /* MBLSettings.m in Sources */, - 55A5EAEE17873EEE0290A88B78E5E47F /* MBLSPIData.m in Sources */, - 3DB5CF33BE913307E82F075D2F01D04E /* MBLStringData.m in Sources */, - 34CF03D6C264FF035EA81D283DD51D73 /* MBLTemperature.m in Sources */, - DDEBCDA02E20A072F33257C605102AB0 /* MBLTemperatureV0.m in Sources */, - 708B5CAEC3C9689E4F1DD1FB01983ADF /* MBLTemperatureV1.m in Sources */, - 7CFD9927AAA45B33B4E745E262C23F00 /* MBLTestDebug.m in Sources */, - 096D3C3E8BE1F5EB6D9D69C45F1E8BE1 /* MBLTimer.m in Sources */, - 3B7FEAF877F9F1A1C6B80582B68ADD8B /* MBLTimerEvent.m in Sources */, - 8F79D376C0EE888418A6556C70FA9F5E /* MBLTriggeredRead.m in Sources */, - 475ECCF39C1C9EFB6618D28B823E4807 /* MetaWearPrivate-dummy.m in Sources */, + 9D3F78280E13C21A6E67051750748ECB /* accelerometer.cpp in Sources */, + 52663842DB5B9243AF609F68828D8490 /* accelerometer_bosch.cpp in Sources */, + B8FF77D7757DB0127BC2A73B7422494B /* accelerometer_mma8452q.cpp in Sources */, + 0BB000DC3091D0547F99099882EF4BB6 /* ambientlight_ltr329.cpp in Sources */, + 27B7E77F819A8046E19839CEE8C6508A /* anonymous_datasignal.cpp in Sources */, + EF15B6B49DE8995CF11B76BA55FBB854 /* async_creator.cpp in Sources */, + CE8321A708B897CB83CE0B7070B5DEC5 /* barometer_bosch.cpp in Sources */, + 312CA7D72386909F69240162AF215A4C /* Bridging.swift in Sources */, + CC3C199126AE869B04775F7EB624CE33 /* cbindings.swift in Sources */, + 86892C0DFD831D8516EC74849253FDD9 /* CBUUID.swift in Sources */, + 8C57BD382B1E923211E9FC1346211BE1 /* colordetector_tcs34725.cpp in Sources */, + CF58C73A6AD2F5E21141E0F584E7C03F /* conductance.cpp in Sources */, + 5EE41E9DF163A29E8B57721D1396221C /* datainterpreter.cpp in Sources */, + 236F810DC748332E00B01A76ECCCB4BD /* dataprocessor.cpp in Sources */, + 462FD0FA28C5564CC92A9D796397862B /* dataprocessor_config.cpp in Sources */, + FB8E1CA1F50552E2A184B5EED802381F /* datasignal.cpp in Sources */, + 40464E3BEC1F490F5CD23190BB86DE68 /* debug.cpp in Sources */, + C6D8FD5291EC0ABDBBB2622C1BB5071D /* DeviceInformation.swift in Sources */, + 12DAC8BAB2F4166AFED414D575436C5E /* dfu_operations.cpp in Sources */, + BA34CF2F245554A7F86056CAD1A081B3 /* dfu_operations_details.cpp in Sources */, + DFBD8D4EE2FFE0DD2D33EFC09EF3308C /* dfu_utility.cpp in Sources */, + A5F3F9F28C467C2B3294D164D0E574C2 /* event.cpp in Sources */, + ED487585601DAA373D1F4B233BA36C20 /* file_operations.cpp in Sources */, + CBB815550C11587460B621667135F8C0 /* gpio.cpp in Sources */, + 1623B23C12E54E3497B668E7A4EDCFAC /* gyro_bosch.cpp in Sources */, + 4D11A2D91AA487292C9EC05730C807A3 /* haptic.cpp in Sources */, + 1F226F537F8460BF4EDE70AF91FC99AF /* humidity_bme280.cpp in Sources */, + D1F5650A0095D2691F9DABB6B430A273 /* ibeacon.cpp in Sources */, + DF319F241395FA2C87858B88D62652AB /* led.cpp in Sources */, + CDE77621403690BFBE5FE3AF54957207 /* LogDelegate.swift in Sources */, + DCA7D1243C9CCD5A9FA134159633BCBD /* logging.cpp in Sources */, + 4789929283ACD4714C32A97CA3F33621 /* macro.cpp in Sources */, + B03D2A549C8060B988688B7E6ED9B2F0 /* magnetometer_bmm150.cpp in Sources */, + 84A1479E822D0E4DE53C9C22CF0143D8 /* MblMwGattChar.swift in Sources */, + 12DB32814292C66A1AE18A03D43CAD62 /* memory.cpp in Sources */, + AE57D9B6AB12C36064C26DA4E1AE3FAE /* MetaWear.swift in Sources */, + 6B7E366017C7AABEE05C43C4B87502F1 /* MetaWear-dummy.m in Sources */, + D2E8A1533C2842208EDE5465065EC9B1 /* metawearboard.cpp in Sources */, + A37E983640B559194177C2A7E2F72FC9 /* MetaWearData.swift in Sources */, + 7E89349F7ECE3F577C190750987E45B6 /* MetaWearScanner.swift in Sources */, + B5CED12449A48B4C5CF3EC41C40C8657 /* miniz.cpp in Sources */, + 9C0AC3E090248A91117CB3F0C8D24648 /* moduleinfo.cpp in Sources */, + C12B2FDD84963FC6CF69851F45E9C7C8 /* multichanneltemperature.cpp in Sources */, + 71C56F0D692B6B529010D83932099612 /* neopixel.cpp in Sources */, + DC712E51ADB04BC6D8E77C5071D80511 /* proximity_tsl2671.cpp in Sources */, + 842C3B7EC7E4FD50372CD78BAF3B2192 /* responseheader.cpp in Sources */, + 4908D6F01808E8B2C82F734B875A8B46 /* sensor_fusion.cpp in Sources */, + D6BA34B49D11A0928AAF296271D59E35 /* serialpassthrough.cpp in Sources */, + CDC4102412F60312687D09D89421D65A /* settings.cpp in Sources */, + C4048C494F0BDB084E14B2BFD4BA6748 /* String+VersionCompare.swift in Sources */, + 3834B3F083EAA0ACA06D0572CA4E061B /* switch.cpp in Sources */, + E63D535FB00AE703521EBEC08AF90092 /* task.cpp in Sources */, + F787290691C3327279C5247437331634 /* threadpool.cpp in Sources */, + 090DCCF33882E1EC2ACD0B10CE7A6D24 /* timer.cpp in Sources */, + 5EC034ADE01051ACBE8D2F2D68105E63 /* utils.cpp in Sources */, + 0E4E66DEC5AC9906D9F1060BF38A05E1 /* version.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 25D59D8872E28BD5F8062BC86259C9FA /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = StaticDataTableViewController; - target = 7121634C8DA4533EB626AEE3C697BFAB /* StaticDataTableViewController */; - targetProxy = B72B2DB8AEEB766DA7B3825A4399A2D5 /* PBXContainerItemProxy */; - }; - 2D047A425F7112B541ED7A844B85406F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = FlexColorPicker; - target = 9A9A6DFBF33C0809BD9B32C8C8B776E8 /* FlexColorPicker */; - targetProxy = 26D9B30409B4FC48E8C4E29203EB465F /* PBXContainerItemProxy */; - }; - 52D55436D59EA269A67CD12FCD9E9395 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = MBProgressHUD; - target = 82B0A41D3031FF27D78E17B0A9A46FB0 /* MBProgressHUD */; - targetProxy = 58E83F60DCD5800A6C4C8868EAEB530C /* PBXContainerItemProxy */; - }; - 61D6476397F039C319662134028750FB /* PBXTargetDependency */ = { + 16CB94919108AE8EECABC7432ED09C8F /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = SQLite.swift; target = 3F2C1776D90B62B156DB52C41A5C419C /* SQLite.swift */; - targetProxy = D6A936BABE57C21FA91A3D5B85C922B9 /* PBXContainerItemProxy */; + targetProxy = FC3AAE0A8D05ADC48DB649184C581E08 /* PBXContainerItemProxy */; }; - 62A8FEEBE8C797886DD868DBC158E50A /* PBXTargetDependency */ = { + 267A5824DDA953BC85B27209E3DEDA57 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = Bolts; - target = 42465A188431886AB035275F049824D3 /* Bolts */; - targetProxy = D4C06B02139C9EFA738B055C77916119 /* PBXContainerItemProxy */; + name = PRTween; + target = 75CA230D0637BEBCCBE6371A0E6B5B6B /* PRTween */; + targetProxy = 010E464B7807A1ACB3A1262CBD7D1E9C /* PBXContainerItemProxy */; }; - 72C660A1C738678A6D3B32E48C8B9F91 /* PBXTargetDependency */ = { + 3E317370606D51A4E332AB0CC85802DC /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = FastCoding; - target = 8CB1610D02CF2E1138DAFFDA5722B39A /* FastCoding */; - targetProxy = 68F9646952DB355BB4ADB27C394FFF1F /* PBXContainerItemProxy */; + name = "Bolts-Swift"; + target = BA1CEDB360B77644C934EAD86B37FCB5 /* Bolts-Swift */; + targetProxy = 25D1465F5BAD756AE9887F8324BA296F /* PBXContainerItemProxy */; }; - 7D603B44299285C250A86A033EA4D91C /* PBXTargetDependency */ = { + 5A7BD700175A01ACC0A85A3A35B7383D /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = Bolts; - target = 42465A188431886AB035275F049824D3 /* Bolts */; - targetProxy = 13CAF08B6968493593A894786C3FDEFB /* PBXContainerItemProxy */; + name = MetaWear; + target = 3E8BB3BAFA6478784A9A7DD76C8A1F3C /* MetaWear */; + targetProxy = 9DDB087D92E14D38907D84D956273CEB /* PBXContainerItemProxy */; }; - 88F81D67FDC9A272DD7CF0DABA7A0D8D /* PBXTargetDependency */ = { + 6AE73402F576A13695BCDAC7C8A2330B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = PRTween; - target = 75CA230D0637BEBCCBE6371A0E6B5B6B /* PRTween */; - targetProxy = F0361704E4EB686B9FEDDB25A4B1F9FC /* PBXContainerItemProxy */; + name = MBProgressHUD; + target = 82B0A41D3031FF27D78E17B0A9A46FB0 /* MBProgressHUD */; + targetProxy = 57CCF59C2EF075AD8E32672C90F88DBE /* PBXContainerItemProxy */; }; - 9B139D32ADF4ADEC9AFBC4F35C58EBC0 /* PBXTargetDependency */ = { + B0A71D24ADECFD8DC49CD98816919705 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = MetaWearPrivate; - target = 5F93A6259A037F8247AD055CC3E8F98E /* MetaWearPrivate */; - targetProxy = E5CE14FF76BF971E6DEEE6A650ED1860 /* PBXContainerItemProxy */; + name = StaticDataTableViewController; + target = 7121634C8DA4533EB626AEE3C697BFAB /* StaticDataTableViewController */; + targetProxy = 6983B19336F847EE094A8132C7989574 /* PBXContainerItemProxy */; }; - E2ADB3953728F3E835E0BF93ACA182E8 /* PBXTargetDependency */ = { + C513F7F2B5456216659494DD1B833389 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = FastCoding; - target = 8CB1610D02CF2E1138DAFFDA5722B39A /* FastCoding */; - targetProxy = FE114F40E0FFAEBA98C12D996359EA72 /* PBXContainerItemProxy */; + name = FlexColorPicker; + target = 9A9A6DFBF33C0809BD9B32C8C8B776E8 /* FlexColorPicker */; + targetProxy = 253BB08B82188324D8CC61B5DEDB276C /* PBXContainerItemProxy */; + }; + FC6D394FA60F863AAE5A8846C37F72B1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Bolts-Swift"; + target = BA1CEDB360B77644C934EAD86B37FCB5 /* Bolts-Swift */; + targetProxy = 7B66B4F4C278ACDE73A87A9588CFF100 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 0074F9D517295A1FBEB856544DFD7BD2 /* Debug */ = { + 0C61EAE1B5D9019E53CC82519550F586 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 4795D991502F3682F21E8D2935999466 /* FastCoding.debug.xcconfig */; + baseConfigurationReference = B4DE3FB54847A63C86EC53E8DC8530D9 /* MetaWear.debug.xcconfig */; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -2841,8 +1472,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/FastCoding/FastCoding-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/FastCoding/FastCoding-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/MetaWear/MetaWear-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/MetaWear/MetaWear-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( @@ -2850,22 +1481,22 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/FastCoding/FastCoding.modulemap"; - PRODUCT_MODULE_NAME = FastCoding; - PRODUCT_NAME = FastCoding; + MODULEMAP_FILE = "Target Support Files/MetaWear/MetaWear.modulemap"; + PRODUCT_MODULE_NAME = MetaWear; + PRODUCT_NAME = MetaWear; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 0839D7318140979F9383A88A0767CEED /* Release */ = { + 0D150F0BA7B8FA0FAA93669AC696EC98 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 252387757419D8BD4A16B5BB34E49F89 /* FastCoding.release.xcconfig */; + baseConfigurationReference = CB8613D5367B50EE420667B174EE11FF /* StaticDataTableViewController.debug.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -2875,8 +1506,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/FastCoding/FastCoding-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/FastCoding/FastCoding-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/StaticDataTableViewController/StaticDataTableViewController-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/StaticDataTableViewController/StaticDataTableViewController-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( @@ -2884,23 +1515,22 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/FastCoding/FastCoding.modulemap"; - PRODUCT_MODULE_NAME = FastCoding; - PRODUCT_NAME = FastCoding; + MODULEMAP_FILE = "Target Support Files/StaticDataTableViewController/StaticDataTableViewController.modulemap"; + PRODUCT_MODULE_NAME = StaticDataTableViewController; + PRODUCT_NAME = StaticDataTableViewController; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Release; + name = Debug; }; - 0D150F0BA7B8FA0FAA93669AC696EC98 /* Debug */ = { + 11D6690C8FB8E0980DAC346E84F273A3 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 79C8049DB69892D6593AFA7630E7932F /* StaticDataTableViewController.debug.xcconfig */; + baseConfigurationReference = 2491E935A0E23ED9309DF4C5E517694E /* FlexColorPicker.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -2910,31 +1540,32 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/StaticDataTableViewController/StaticDataTableViewController-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/StaticDataTableViewController/StaticDataTableViewController-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/FlexColorPicker/FlexColorPicker-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/FlexColorPicker/FlexColorPicker-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 17.6; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/StaticDataTableViewController/StaticDataTableViewController.modulemap"; - PRODUCT_MODULE_NAME = StaticDataTableViewController; - PRODUCT_NAME = StaticDataTableViewController; + MODULEMAP_FILE = "Target Support Files/FlexColorPicker/FlexColorPicker.modulemap"; + PRODUCT_MODULE_NAME = FlexColorPicker; + PRODUCT_NAME = FlexColorPicker; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Debug; + name = Release; }; - 11D6690C8FB8E0980DAC346E84F273A3 /* Release */ = { + 223D7187818B65186C256528391D1661 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 4E38AEA2BBA3C0224D73CD1875E2B759 /* FlexColorPicker.release.xcconfig */; + baseConfigurationReference = D8ED150D37C2259786E97A605A2E86B1 /* Bolts-Swift.debug.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -2944,8 +1575,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/FlexColorPicker/FlexColorPicker-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/FlexColorPicker/FlexColorPicker-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/Bolts-Swift/Bolts-Swift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Bolts-Swift/Bolts-Swift-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( @@ -2953,23 +1584,22 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/FlexColorPicker/FlexColorPicker.modulemap"; - PRODUCT_MODULE_NAME = FlexColorPicker; - PRODUCT_NAME = FlexColorPicker; + MODULEMAP_FILE = "Target Support Files/Bolts-Swift/Bolts-Swift.modulemap"; + PRODUCT_MODULE_NAME = BoltsSwift; + PRODUCT_NAME = BoltsSwift; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Release; + name = Debug; }; 23C4262324919D1009585AF56B92B49A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1A7459BA29DBA3A3E33E19765B2D9FE3 /* StaticDataTableViewController.release.xcconfig */; + baseConfigurationReference = 2592765ADE2B014E4E4341340C29238A /* StaticDataTableViewController.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -3004,7 +1634,7 @@ }; 2705B82FAD3E374C3BF6B225CAFAFDC4 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 62BD501B622AE2197A8251EBEBC98B30 /* MBProgressHUD.release.xcconfig */; + baseConfigurationReference = 5349A2FBCECBAF0D2A07BF2B4B1861A7 /* MBProgressHUD.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -3039,7 +1669,7 @@ }; 2EE9461356CC7706CA62E729B5C52302 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 192865505A11585EE708054437C64D0B /* SQLite.swift.debug.xcconfig */; + baseConfigurationReference = 44850702D275D1B542895C838EDE8E50 /* SQLite.swift.debug.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -3072,7 +1702,7 @@ }; 2F85FD60FCD2819C096470B5073C7DFD /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = FBB30E58B8EB0EB21BE9FA3DE85AF8D6 /* MBProgressHUD.debug.xcconfig */; + baseConfigurationReference = 7F27C589134A2FEE1DBD415460594611 /* MBProgressHUD.debug.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -3106,7 +1736,7 @@ }; 34E159C4F20578379EC0D11FD3B91A1F /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 879B08BDF7758C925448C0BFEE3B29EB /* FlexColorPicker.debug.xcconfig */; + baseConfigurationReference = CF7FAC8D2FF0282B7BE0648778AFD80A /* FlexColorPicker.debug.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -3119,7 +1749,7 @@ GCC_PREFIX_HEADER = "Target Support Files/FlexColorPicker/FlexColorPicker-prefix.pch"; INFOPLIST_FILE = "Target Support Files/FlexColorPicker/FlexColorPicker-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 17.6; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -3138,9 +1768,9 @@ }; name = Debug; }; - 3655082220CFB85DB7BF4F8D9ECC9D5B /* Debug */ = { + 6511A7793D1F3532CEB0ACDCEEE74611 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2B7F010F3BCC8E3ED586A840E274BACE /* MetaWearPrivate.debug.xcconfig */; + baseConfigurationReference = 33D59C5EE9504CAE85DD5EC3A8B2619D /* PRTween.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -3150,8 +1780,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/MetaWearPrivate/MetaWearPrivate-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/MetaWearPrivate/MetaWearPrivate-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/PRTween/PRTween-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/PRTween/PRTween-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( @@ -3159,9 +1789,79 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/MetaWearPrivate/MetaWearPrivate.modulemap"; - PRODUCT_MODULE_NAME = MetaWear; - PRODUCT_NAME = MetaWear; + MODULEMAP_FILE = "Target Support Files/PRTween/PRTween.modulemap"; + PRODUCT_MODULE_NAME = PRTween; + PRODUCT_NAME = PRTween; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 6DC126EE49BC0BD002DA05E10065B3C9 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 18D894726DE00A174BEAABE67F40DF6C /* Bolts-Swift.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/Bolts-Swift/Bolts-Swift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Bolts-Swift/Bolts-Swift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/Bolts-Swift/Bolts-Swift.modulemap"; + PRODUCT_MODULE_NAME = BoltsSwift; + PRODUCT_NAME = BoltsSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 7F77493EF6408ABEE603A740D706B0AF /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6DCABDA1D6ACE795F49425A95926630A /* PRTween.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/PRTween/PRTween-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/PRTween/PRTween-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 17.6; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PRTween/PRTween.modulemap"; + PRODUCT_MODULE_NAME = PRTween; + PRODUCT_NAME = PRTween; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; @@ -3172,7 +1872,7 @@ }; name = Debug; }; - 4BC7450F9457737EE3E637BA155B56F7 /* Debug */ = { + 8C9963745FD01B6B3EF95F9CE58D9F10 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -3238,42 +1938,7 @@ }; name = Debug; }; - 6511A7793D1F3532CEB0ACDCEEE74611 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7095B1A9FFD67603BD83BD4F313E1E8E /* PRTween.release.xcconfig */; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/PRTween/PRTween-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/PRTween/PRTween-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 17.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULEMAP_FILE = "Target Support Files/PRTween/PRTween.modulemap"; - PRODUCT_MODULE_NAME = PRTween; - PRODUCT_NAME = PRTween; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 75BE0C6978F95F4B4C35146319F0A595 /* Release */ = { + B09B7A810831A1C20E085C71A370751D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AAC68B97AFA7C06A7C3CB3024300B34 /* Pods-MusicalCaneGame.release.xcconfig */; buildSettings = { @@ -3311,110 +1976,7 @@ }; name = Release; }; - 7F77493EF6408ABEE603A740D706B0AF /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 6C76C0FCB90D1002A9C4A440C1A2AA92 /* PRTween.debug.xcconfig */; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/PRTween/PRTween-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/PRTween/PRTween-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 17.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULEMAP_FILE = "Target Support Files/PRTween/PRTween.modulemap"; - PRODUCT_MODULE_NAME = PRTween; - PRODUCT_NAME = PRTween; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 8252368996B2DA669E7C33BD71A56877 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 2DA2162B1DE380D357939F9498BD8311 /* Bolts.release.xcconfig */; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/Bolts/Bolts-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/Bolts/Bolts-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 17.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULEMAP_FILE = "Target Support Files/Bolts/Bolts.modulemap"; - PRODUCT_MODULE_NAME = Bolts; - PRODUCT_NAME = Bolts; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 885670CE1FCBC1FA3C49CFEBD36F7A8D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 43968FC5841B33AC860F8B17B9CA2E76 /* Bolts.debug.xcconfig */; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/Bolts/Bolts-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/Bolts/Bolts-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 17.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULEMAP_FILE = "Target Support Files/Bolts/Bolts.modulemap"; - PRODUCT_MODULE_NAME = Bolts; - PRODUCT_NAME = Bolts; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.0; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 8B5A46FF8D3C1289CDEE3BAFACABCD2A /* Release */ = { + B9F3557045385CA606F5AF548D58B58A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -3476,10 +2038,11 @@ }; name = Release; }; - 903A312B33E678D0A67A936A6608745F /* Release */ = { + BF9DF2CB686E72F49C57963053031311 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 493E9D78B13733C59AB3A986CB697840 /* MetaWearPrivate.release.xcconfig */; + baseConfigurationReference = 3EA827C8B3D6F7A27497CC460A903E67 /* MetaWear.release.xcconfig */; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -3488,8 +2051,8 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/MetaWearPrivate/MetaWearPrivate-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/MetaWearPrivate/MetaWearPrivate-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/MetaWear/MetaWear-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/MetaWear/MetaWear-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 17.6; LD_RUNPATH_SEARCH_PATHS = ( @@ -3497,13 +2060,13 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/MetaWearPrivate/MetaWearPrivate.modulemap"; + MODULEMAP_FILE = "Target Support Files/MetaWear/MetaWear.modulemap"; PRODUCT_MODULE_NAME = MetaWear; PRODUCT_NAME = MetaWear; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -3513,7 +2076,7 @@ }; D18FE1B2B9D7A12FF115587BA66C407D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9E05B40C0330E22A967C1E33D89416D5 /* SQLite.swift.release.xcconfig */; + baseConfigurationReference = 12B347F97086190A06909E4EC2E6D349 /* SQLite.swift.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -3545,7 +2108,7 @@ }; name = Release; }; - EFFE9E3D7295D60FFD34F6631B058540 /* Debug */ = { + DD4FE6EFBF41EEEB22F9A816D1FF90E0 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = B5675162CF07A333A600854AC822CAF5 /* Pods-MusicalCaneGame.debug.xcconfig */; buildSettings = { @@ -3594,11 +2157,11 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 1AD87D09F1FD2A9FE3A07101B961DED4 /* Build configuration list for PBXNativeTarget "FastCoding" */ = { + 12DB945DF6C6F5198BAEAC2F2D8C2F12 /* Build configuration list for PBXNativeTarget "Pods-MusicalCaneGame" */ = { isa = XCConfigurationList; buildConfigurations = ( - 0074F9D517295A1FBEB856544DFD7BD2 /* Debug */, - 0839D7318140979F9383A88A0767CEED /* Release */, + DD4FE6EFBF41EEEB22F9A816D1FF90E0 /* Debug */, + B09B7A810831A1C20E085C71A370751D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -3633,17 +2196,17 @@ 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( - 4BC7450F9457737EE3E637BA155B56F7 /* Debug */, - 8B5A46FF8D3C1289CDEE3BAFACABCD2A /* Release */, + 8C9963745FD01B6B3EF95F9CE58D9F10 /* Debug */, + B9F3557045385CA606F5AF548D58B58A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - A48BFDDB7FA0FDDFBE8F2C4A5A84883F /* Build configuration list for PBXNativeTarget "Pods-MusicalCaneGame" */ = { + 753A955E3C890042144DB875D1ED351A /* Build configuration list for PBXNativeTarget "MetaWear" */ = { isa = XCConfigurationList; buildConfigurations = ( - EFFE9E3D7295D60FFD34F6631B058540 /* Debug */, - 75BE0C6978F95F4B4C35146319F0A595 /* Release */, + 0C61EAE1B5D9019E53CC82519550F586 /* Debug */, + BF9DF2CB686E72F49C57963053031311 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -3657,20 +2220,11 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - C64E84974E44FEF637DB6271C8FDF930 /* Build configuration list for PBXNativeTarget "MetaWearPrivate" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3655082220CFB85DB7BF4F8D9ECC9D5B /* Debug */, - 903A312B33E678D0A67A936A6608745F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EFB970C8C306436F33E2A0084A838F7D /* Build configuration list for PBXNativeTarget "Bolts" */ = { + C48222D97D3730ADFA867FB3A54056D0 /* Build configuration list for PBXNativeTarget "Bolts-Swift" */ = { isa = XCConfigurationList; buildConfigurations = ( - 885670CE1FCBC1FA3C49CFEBD36F7A8D /* Debug */, - 8252368996B2DA669E7C33BD71A56877 /* Release */, + 223D7187818B65186C256528391D1661 /* Debug */, + 6DC126EE49BC0BD002DA05E10065B3C9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/Bolts-Swift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/Bolts-Swift.xcscheme new file mode 100644 index 0000000..a5d045f --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/Bolts-Swift.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/FlexColorPicker.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/FlexColorPicker.xcscheme new file mode 100644 index 0000000..e0c2f61 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/FlexColorPicker.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/MBProgressHUD.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/MBProgressHUD.xcscheme new file mode 100644 index 0000000..d566028 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/MBProgressHUD.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/MetaWear.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/MetaWear.xcscheme new file mode 100644 index 0000000..3e80c06 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/MetaWear.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/PRTween.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/PRTween.xcscheme new file mode 100644 index 0000000..a4b1f66 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/PRTween.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/Pods-MusicalCaneGame.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/Pods-MusicalCaneGame.xcscheme new file mode 100644 index 0000000..aa1f86c --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/Pods-MusicalCaneGame.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/SQLite.swift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/SQLite.swift.xcscheme new file mode 100644 index 0000000..68c0383 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/SQLite.swift.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/StaticDataTableViewController.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/StaticDataTableViewController.xcscheme new file mode 100644 index 0000000..e2d6c7b --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/StaticDataTableViewController.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/xcschememanagement.plist b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..a9284ab --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/occamlab.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,51 @@ + + + + + SchemeUserState + + Bolts-Swift.xcscheme + + isShown + + + FlexColorPicker.xcscheme + + isShown + + + MBProgressHUD.xcscheme + + isShown + + + MetaWear.xcscheme + + isShown + + + PRTween.xcscheme + + isShown + + + Pods-MusicalCaneGame.xcscheme + + isShown + + + SQLite.swift.xcscheme + + isShown + + + StaticDataTableViewController.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + + diff --git a/Pods/StaticDataTableViewController/LICENSE.txt b/Pods/StaticDataTableViewController/LICENSE.txt new file mode 100644 index 0000000..d8888ab --- /dev/null +++ b/Pods/StaticDataTableViewController/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2015 Peter Paulis - min60 s.r.o. (min60.com) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/StaticDataTableViewController/README.md b/Pods/StaticDataTableViewController/README.md new file mode 100644 index 0000000..bade1ed --- /dev/null +++ b/Pods/StaticDataTableViewController/README.md @@ -0,0 +1,76 @@ +StaticDataTableViewController 2.0 +============================= + +This class enables animated hide/show of static cells (created in IB, using the option Content : Static cells) for UITableView + +##Usage + +- add StaticDataTableViewController.h / .m to your project +- just subclass your UITableViewController with the StaticDataTableViewController +- always use this method for table view reload (- (void)reloadDataAnimated:(BOOL)animated) don't call [self.tableView reloadData] + +to hide/show specific cells, to which you have an outlet +``` objective-c +self.hideSectionsWithHiddenRows = YES; //YES, NO +[self cell:self.outletToMyStaticCell1 setHidden:hide]; +[self cell:self.outletToMyStaticCell2 setHidden:hide]; +[self reloadDataAnimated:YES]; +``` + +to hide/show cells in an outlet collection +``` objective-c +self.hideSectionsWithHiddenRows = YES; //YES, NO +[self cells:self.outletCollectionToMyStaticCells setHidden:hide]; +[self reloadDataAnimated:YES]; +``` + +to reload cell in an outlet collection +``` objective-c +[self updateCells:self.outletCollectionToMyStaticCells]; +[self reloadDataAnimated:YES]; +``` + +to customize animations, just set these properties to desired values +``` objective-c +self.insertTableViewRowAnimation = UITableViewRowAnimationRight; +self.deleteTableViewRowAnimation = UITableViewRowAnimationLeft; +self.reloadTableViewRowAnimation = UITableViewRowAnimationMiddle; +``` + +##Version History + +Version 2.0.5 +- added support for changing / setting cell height + +Version 2.0.4 +- added section headers animation support + +Version 2.0.3 +- semantic version tagging + +Version 2.0.2.1 +- Added support for Cocoa pods + +Version 2.0.2 +- Added support for variable heights on static rows + +Version 2.0.1 +- fixed critical bug + +Version 2.0 +- added full row animation support + +Version 1.1 +- added iOS5 back compatibility +- added support for IBOutletCollections and hidding multiple cells with an array of IBOutles + +##Note +- Create outlets to UITableViewsCells, not their content views! +- Don't call [self.tableView reloadData], ALWAYS use (reloadDataAnimated:) +- if you want to hide the whole section, just create a IBOutletCollection to all its cell, and then use [self cells:setHidden:] with (self.hideSectionsWithHiddenRows = YES) + +##License +Apache License 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt + +##Credits +min:60 - Building perfect apps, for affordable price - https://min60.com diff --git a/Pods/StaticDataTableViewController/StaticDataTableViewController.h b/Pods/StaticDataTableViewController/StaticDataTableViewController.h new file mode 100755 index 0000000..abdf70c --- /dev/null +++ b/Pods/StaticDataTableViewController/StaticDataTableViewController.h @@ -0,0 +1,60 @@ +// +// StaticTableViewController.h +// StaticTableViewController 2.0 +// +// Created by Peter Paulis on 31.1.2013. +// Copyright (c) 2013 Peter Paulis. All rights reserved. +// + +#import + +@interface StaticDataTableViewController : UITableViewController + + +@property (nonatomic, assign) UITableViewRowAnimation insertTableViewRowAnimation; + +@property (nonatomic, assign) UITableViewRowAnimation reloadTableViewRowAnimation; + +@property (nonatomic, assign) UITableViewRowAnimation deleteTableViewRowAnimation; + + +// Shown / Hidden +- (void)cell:(nonnull UITableViewCell *)cell setHidden:(BOOL)hidden; + +- (void)cells:(nonnull NSArray *)cells setHidden:(BOOL)hidden; + +- (BOOL)isCellHidden:(nonnull UITableViewCell *)cell; + + +// Height +- (void)cell:(nonnull UITableViewCell *)cell setHeight:(CGFloat)height; + +- (void)cells:(nonnull NSArray *)cells setHeight:(CGFloat)height; + + +// Update +- (void)updateCell:(nonnull UITableViewCell *)cell; + +- (void)updateCells:(nonnull NSArray *)cells; + + +// Reload +// never call [self.tableView reloadData] directly +// doing so will lead to data inconsistency +// ALWAYS! use this method for reload! +- (void)reloadDataAnimated:(BOOL)animated; + +- (void)reloadDataAnimated:(BOOL)animated insertAnimation:(UITableViewRowAnimation)insertAnimation reloadAnimation:(UITableViewRowAnimation)reloadAnimation deleteAnimation:(UITableViewRowAnimation)deleteAnimation; + + +// you may want to overwrite these two methods in your subclass, to provide custom logic (eg. force the header or footer to be shown, even when no cell are vissible) +- (BOOL)showHeaderForSection:(NSInteger)section vissibleRows:(NSInteger)vissibleRows; +- (BOOL)showFooterForSection:(NSInteger)section vissibleRows:(NSInteger)vissibleRows; + + +// Depracated +@property (nonatomic, assign) BOOL animateSectionHeaders DEPRECATED_ATTRIBUTE; +@property (nonatomic, assign) BOOL hideSectionsWithHiddenRows DEPRECATED_ATTRIBUTE; // use showHeaderForSection:vissibleRows: and showFooterForSection::vissibleRows: +- (BOOL)cellIsHidden:(nonnull UITableViewCell *)cell DEPRECATED_ATTRIBUTE; // use isCellHidden: + +@end diff --git a/Pods/StaticDataTableViewController/StaticDataTableViewController.m b/Pods/StaticDataTableViewController/StaticDataTableViewController.m new file mode 100755 index 0000000..4b6dab7 --- /dev/null +++ b/Pods/StaticDataTableViewController/StaticDataTableViewController.m @@ -0,0 +1,598 @@ +// +// StaticTableViewController.m +// StaticTableViewController 2.0 +// +// Created by Peter Paulis on 31.1.2013. +// Copyright (c) 2013 Peter Paulis. All rights reserved. +// + +#import "StaticDataTableViewController.h" + +#define kBatchOperationNone 0 +#define kBatchOperationInsert 1 +#define kBatchOperationDelete 2 +#define kBatchOperationUpdate 3 + +//////////////////////////////////////////////////////////////////////// +#pragma mark - OriginalRow +//////////////////////////////////////////////////////////////////////// + +@interface OriginalRow : NSObject + +@property (nonatomic, assign) BOOL hidden; + +@property (nonatomic, assign) BOOL hiddenReal; + +@property (nonatomic, assign) BOOL hiddenPlanned; + +@property (nonatomic, assign) int batchOperation; + +@property (nonatomic, weak) UITableViewCell * cell; + +@property (nonatomic, strong) NSIndexPath * originalIndexPath; + +@property (nonatomic, assign) CGFloat height; + +- (void)update; + +@end + +@implementation OriginalRow + +- (id)init { + self = [super init]; + + if (self) { + self.height = CGFLOAT_MAX; + } + + return self; +} + +- (BOOL)hidden { + return (self.hiddenPlanned); +} + +- (void)setHidden:(BOOL)hidden { + + if ((!self.hiddenReal) && (hidden)) { + self.batchOperation = kBatchOperationDelete; + } else if ((self.hiddenReal) && (!hidden)) { + self.batchOperation = kBatchOperationInsert; + } + + self.hiddenPlanned = hidden; +} + +- (void)update { + + if (!self.hidden) { + if (self.batchOperation == kBatchOperationNone) { + self.batchOperation = kBatchOperationUpdate; + } + } +} + +@end + +//////////////////////////////////////////////////////////////////////// +#pragma mark - OriginalSection +//////////////////////////////////////////////////////////////////////// + +@interface OriginalSection : NSObject + +@property (nonatomic, strong) NSString * label; + +@property (nonatomic, strong) NSMutableArray * rows; + +@end + +@implementation OriginalSection + +- (NSInteger)numberOfVissibleRows { + NSInteger count = 0; + for (OriginalRow * or in self.rows) { + if (!or.hidden) { + ++count; + } + } + + return count; +} + +- (NSInteger)vissibleRowIndexWithTableViewCell:(UITableViewCell *)cell { + + NSInteger i = 0; + for (OriginalRow * or in self.rows) { + + if (or.cell == cell) { + return i; + } + + if (!or.hidden) { + ++i; + } + } + + return -1; +} + +@end + +//////////////////////////////////////////////////////////////////////// +#pragma mark - OriginalTable +//////////////////////////////////////////////////////////////////////// + +@interface OriginalTable : NSObject + +@property (nonatomic, strong) NSMutableArray * sections; + +@property (nonatomic, weak) UITableView * tableView; + +@property (nonatomic, strong) NSMutableArray * insertIndexPaths; + +@property (nonatomic, strong) NSMutableArray * deleteIndexPaths; + +@property (nonatomic, strong) NSMutableArray * updateIndexPaths; + +@property (nonatomic, strong) NSMutableArray * reloadSectionsIndexes; + +@end + +@implementation OriginalTable + +- (id)initWithTableView:(UITableView *)tableView { + + self = [super init]; + if (self) { + + NSInteger numberOfSections = [tableView numberOfSections]; + self.sections = [[NSMutableArray alloc] initWithCapacity:numberOfSections]; + + NSInteger totalNumberOfRows = 0; + for (NSInteger i = 0; i < numberOfSections; ++i) { + OriginalSection * originalSection = [OriginalSection new]; + + NSInteger numberOfRows = [tableView numberOfRowsInSection:i]; + totalNumberOfRows += numberOfRows; + originalSection.rows = [[NSMutableArray alloc] initWithCapacity:numberOfRows]; + for (NSInteger ii = 0; ii < numberOfRows; ++ii) { + OriginalRow * tableViewRow = [OriginalRow new]; + + NSIndexPath * ip = [NSIndexPath indexPathForRow:ii inSection:i]; + tableViewRow.cell = [tableView.dataSource tableView:tableView cellForRowAtIndexPath:ip]; + + NSAssert(tableViewRow.cell != nil, @"cannot be nil"); + + tableViewRow.originalIndexPath = [NSIndexPath indexPathForRow:ii inSection:i]; + + originalSection.rows[ii] = tableViewRow; + } + + self.sections[i] = originalSection; + } + + self.insertIndexPaths = [[NSMutableArray alloc] initWithCapacity:totalNumberOfRows]; + self.deleteIndexPaths = [[NSMutableArray alloc] initWithCapacity:totalNumberOfRows]; + self.updateIndexPaths = [[NSMutableArray alloc] initWithCapacity:totalNumberOfRows]; + self.reloadSectionsIndexes = [[NSMutableArray alloc] initWithCapacity:numberOfSections]; + + self.tableView = tableView; + + } + + return self; +} + +- (OriginalRow *)originalRowWithIndexPath:(NSIndexPath *)indexPath { + + OriginalSection * oSection = self.sections[indexPath.section]; + OriginalRow * oRow = oSection.rows[indexPath.row]; + + return oRow; +} + +- (OriginalRow *)vissibleOriginalRowWithIndexPath:(NSIndexPath *)indexPath { + + OriginalSection * oSection = self.sections[indexPath.section]; + NSInteger vissibleIndex = -1; + for (int i = 0; i < [oSection.rows count]; ++i) { + + OriginalRow * oRow = [oSection.rows objectAtIndex:i]; + + if (!oRow.hidden) { + ++vissibleIndex; + } + + if (indexPath.row == vissibleIndex) { + return oRow; + } + + } + + return nil; +} + +- (OriginalRow *)originalRowWithTableViewCell:(UITableViewCell *)cell { + + for (NSInteger i = 0; i < [self.sections count]; ++i) { + + OriginalSection * os = self.sections[i]; + + for (NSInteger ii = 0; ii < [os.rows count]; ++ii) { + + if ([os.rows[ii] cell] == cell) { + return os.rows[ii]; + } + + } + + } + + return nil; +} + +- (NSIndexPath *)indexPathForInsertingOriginalRow:(OriginalRow *)originalRow { + + OriginalSection * oSection = self.sections[originalRow.originalIndexPath.section]; + NSInteger vissibleIndex = -1; + for (NSInteger i = 0; i < originalRow.originalIndexPath.row; ++i) { + + OriginalRow * oRow = [oSection.rows objectAtIndex:i]; + + if (!oRow.hidden) { + ++vissibleIndex; + } + + } + + return [NSIndexPath indexPathForRow:vissibleIndex + 1 inSection:originalRow.originalIndexPath.section]; + +} + +- (NSIndexPath *)indexPathForDeletingOriginalRow:(OriginalRow *)originalRow { + + OriginalSection * oSection = self.sections[originalRow.originalIndexPath.section]; + NSInteger vissibleIndex = -1; + for (NSInteger i = 0; i < originalRow.originalIndexPath.row; ++i) { + + OriginalRow * oRow = [oSection.rows objectAtIndex:i]; + + if (!oRow.hiddenReal) { + ++vissibleIndex; + } + + } + + return [NSIndexPath indexPathForRow:vissibleIndex + 1 inSection:originalRow.originalIndexPath.section]; + +} + +- (void)prepareUpdates { + + [self.insertIndexPaths removeAllObjects]; + [self.deleteIndexPaths removeAllObjects]; + [self.updateIndexPaths removeAllObjects]; + + [self.reloadSectionsIndexes removeAllObjects]; + + NSInteger sectionIndex = 0; + for (OriginalSection * os in self.sections) { + + BOOL visibleBefore = NO; + BOOL visibleAfter = NO; + + for (OriginalRow * or in os.rows) { + + visibleBefore = visibleBefore || !or.hiddenReal; + + if (or.batchOperation == kBatchOperationDelete) { + + NSIndexPath * ip = [self indexPathForDeletingOriginalRow:or]; + [self.deleteIndexPaths addObject:ip]; + + } else if (or.batchOperation == kBatchOperationInsert) { + + NSIndexPath * ip = [self indexPathForInsertingOriginalRow:or]; + [self.insertIndexPaths addObject:ip]; + + } else if (or.batchOperation == kBatchOperationUpdate) { + + NSIndexPath * ip = [self indexPathForInsertingOriginalRow:or]; + [self.updateIndexPaths addObject:ip]; + + } + + visibleAfter = visibleAfter || !or.hiddenPlanned; + + } + + if (visibleBefore != visibleAfter) { + [self.reloadSectionsIndexes addObject:@(sectionIndex)]; + } + ++sectionIndex; + + } + + // we must do this AFTER all updates calculations, so the indexes dont mess up + for (OriginalSection * os in self.sections) { + + for (OriginalRow * or in os.rows) { + + or.hiddenReal = or.hiddenPlanned; + or.batchOperation = kBatchOperationNone; + + } + + } + +} + +@end + +//////////////////////////////////////////////////////////////////////// +#pragma mark - StaticDataTableViewController +//////////////////////////////////////////////////////////////////////// + +@interface StaticDataTableViewController () + +@property (nonatomic, strong) OriginalTable * originalTable; + +@end + +@implementation StaticDataTableViewController + +- (id)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:style]; + if (self) { + + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.insertTableViewRowAnimation = UITableViewRowAnimationRight; + self.deleteTableViewRowAnimation = UITableViewRowAnimationLeft; + self.reloadTableViewRowAnimation = UITableViewRowAnimationMiddle; + + self.originalTable = [[OriginalTable alloc] initWithTableView:self.tableView]; + +} + +//////////////////////////////////////////////////////////////////////// +#pragma mark - Public +//////////////////////////////////////////////////////////////////////// + +- (void)updateCell:(UITableViewCell *)cell { + + OriginalRow * row = [self.originalTable originalRowWithTableViewCell:cell]; + [row update]; + +} + +- (void)updateCells:(NSArray *)cells { + for (UITableViewCell * cell in cells) { + [self updateCell:cell]; + } +} + +- (void)cell:(UITableViewCell *)cell setHidden:(BOOL)hidden { + + OriginalRow * row = [self.originalTable originalRowWithTableViewCell:cell]; + [row setHidden:hidden]; + +} + +- (void)cells:(NSArray *)cells setHidden:(BOOL)hidden { + for (UITableViewCell * cell in cells) { + [self cell:cell setHidden:hidden]; + } +} + +- (void)cell:(UITableViewCell *)cell setHeight:(CGFloat)height { + + OriginalRow * row = [self.originalTable originalRowWithTableViewCell:cell]; + [row setHeight:height]; + +} + +- (void)cells:(NSArray *)cells setHeight:(CGFloat)height { + for (UITableViewCell * cell in cells) { + [self cell:cell setHeight:height]; + } +} + +- (BOOL)cellIsHidden:(UITableViewCell *)cell { + return [[self.originalTable originalRowWithTableViewCell:cell] hidden]; +} + +- (BOOL)isCellHidden:(UITableViewCell *)cell { + return [[self.originalTable originalRowWithTableViewCell:cell] hidden]; +} + +- (void)reloadDataAnimated:(BOOL)animated { + + [self reloadDataAnimated:animated insertAnimation:self.insertTableViewRowAnimation reloadAnimation:self.reloadTableViewRowAnimation deleteAnimation:self.deleteTableViewRowAnimation]; + +} + +- (void)reloadDataAnimated:(BOOL)animated insertAnimation:(UITableViewRowAnimation)insertAnimation reloadAnimation:(UITableViewRowAnimation)reloadAnimation deleteAnimation:(UITableViewRowAnimation)deleteAnimation { + + [self.originalTable prepareUpdates]; + + if (!animated) { + + [self.tableView reloadData]; + + } else { + + [self.tableView beginUpdates]; + + [self.tableView reloadRowsAtIndexPaths:self.originalTable.updateIndexPaths withRowAnimation:reloadAnimation]; + + [self.tableView insertRowsAtIndexPaths:self.originalTable.insertIndexPaths withRowAnimation:insertAnimation]; + + [self.tableView deleteRowsAtIndexPaths:self.originalTable.deleteIndexPaths withRowAnimation:deleteAnimation]; + + if ([self.originalTable.reloadSectionsIndexes count] > 0) { + + for (NSNumber * i in self.originalTable.reloadSectionsIndexes) { + [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:[i integerValue]] withRowAnimation:self.reloadTableViewRowAnimation]; + } + + } + + [self.tableView endUpdates]; + + } + +} + +//////////////////////////////////////////////////////////////////////// +#pragma mark - Public / Should Overwrite +//////////////////////////////////////////////////////////////////////// + +- (BOOL)showHeaderForSection:(NSInteger)section vissibleRows:(NSInteger)vissibleRows { + return vissibleRows > 0; +} + +- (BOOL)showFooterForSection:(NSInteger)section vissibleRows:(NSInteger)vissibleRows { + return vissibleRows > 0; +} + +//////////////////////////////////////////////////////////////////////// +#pragma mark - TableView Data Source +//////////////////////////////////////////////////////////////////////// + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + + if (self.originalTable == nil) { + return [super tableView:tableView numberOfRowsInSection:section]; + } + + return [self.originalTable.sections[section] numberOfVissibleRows]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + if (self.originalTable == nil) { + return [super tableView:tableView cellForRowAtIndexPath:indexPath]; + } + + OriginalRow * or = [self.originalTable vissibleOriginalRowWithIndexPath:indexPath]; + + NSAssert(or.cell != nil, @"Original cell cannot be nil, make sure to use a static table view"); + + return or.cell; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + + if (self.originalTable != nil) { + OriginalRow * or = [self.originalTable vissibleOriginalRowWithIndexPath:indexPath]; + + if (or.height != CGFLOAT_MAX) { + return or.height; + } + + indexPath = or.originalIndexPath; + } + return [super tableView:tableView heightForRowAtIndexPath:indexPath]; +} + + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { + + if (self.originalTable == nil) { + return [super tableView:tableView titleForHeaderInSection:section]; + } + + OriginalSection * os = self.originalTable.sections[section]; + if ([self showHeaderForSection:section vissibleRows:[os numberOfVissibleRows]]) { + return [super tableView:tableView titleForHeaderInSection:section]; + } else { + return nil; + } + +} + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + + if (self.originalTable == nil) { + return [super tableView:tableView viewForHeaderInSection:section]; + } + + OriginalSection * os = self.originalTable.sections[section]; + if ([self showHeaderForSection:section vissibleRows:[os numberOfVissibleRows]]) { + return [super tableView:tableView viewForHeaderInSection:section]; + } else { + return nil; + } + +} + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + + if (self.originalTable == nil) { + return [super tableView:tableView heightForHeaderInSection:section]; + } + + OriginalSection * os = self.originalTable.sections[section]; + if ([self showHeaderForSection:section vissibleRows:[os numberOfVissibleRows]]) { + return [super tableView:tableView heightForHeaderInSection:section]; + } else { + return CGFLOAT_MIN; + } + +} + +- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { + + if (self.originalTable == nil) { + return [super tableView:tableView titleForFooterInSection:section]; + } + + OriginalSection * os = self.originalTable.sections[section]; + if ([self showFooterForSection:section vissibleRows:[os numberOfVissibleRows]]) { + return [super tableView:tableView titleForFooterInSection:section]; + } else { + return nil; + } + +} + +- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { + + if (self.originalTable == nil) { + return [super tableView:tableView viewForFooterInSection:section]; + } + + OriginalSection * os = self.originalTable.sections[section]; + if ([self showFooterForSection:section vissibleRows:[os numberOfVissibleRows]]) { + return [super tableView:tableView viewForFooterInSection:section]; + } else { + return nil; + } + +} + +- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { + + if (self.originalTable == nil) { + return [super tableView:tableView heightForFooterInSection:section]; + } + + OriginalSection * os = self.originalTable.sections[section]; + if ([self showHeaderForSection:section vissibleRows:[os numberOfVissibleRows]]) { + return [super tableView:tableView heightForFooterInSection:section]; + } else { + return CGFLOAT_MIN; + } + +} + +@end diff --git a/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-Info.plist b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-Info.plist new file mode 100644 index 0000000..947950f --- /dev/null +++ b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.5.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-dummy.m b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-dummy.m new file mode 100644 index 0000000..2af8dec --- /dev/null +++ b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Bolts_Swift : NSObject +@end +@implementation PodsDummy_Bolts_Swift +@end diff --git a/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-prefix.pch b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-umbrella.h b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-umbrella.h new file mode 100644 index 0000000..7acccef --- /dev/null +++ b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double BoltsSwiftVersionNumber; +FOUNDATION_EXPORT const unsigned char BoltsSwiftVersionString[]; + diff --git a/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.debug.xcconfig b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.debug.xcconfig new file mode 100644 index 0000000..9f5e2c9 --- /dev/null +++ b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.debug.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Bolts-Swift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Bolts-Swift +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.modulemap b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.modulemap new file mode 100644 index 0000000..e8392ae --- /dev/null +++ b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.modulemap @@ -0,0 +1,6 @@ +framework module BoltsSwift { + umbrella header "Bolts-Swift-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.release.xcconfig b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.release.xcconfig new file mode 100644 index 0000000..9f5e2c9 --- /dev/null +++ b/Pods/Target Support Files/Bolts-Swift/Bolts-Swift.release.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Bolts-Swift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Bolts-Swift +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-Info.plist b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-Info.plist new file mode 100644 index 0000000..2c7aaa6 --- /dev/null +++ b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.4.4 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-dummy.m b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-dummy.m new file mode 100644 index 0000000..fc03874 --- /dev/null +++ b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FlexColorPicker : NSObject +@end +@implementation PodsDummy_FlexColorPicker +@end diff --git a/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-prefix.pch b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-umbrella.h b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-umbrella.h new file mode 100644 index 0000000..655199e --- /dev/null +++ b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker-umbrella.h @@ -0,0 +1,17 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FlexColorPicker.h" + +FOUNDATION_EXPORT double FlexColorPickerVersionNumber; +FOUNDATION_EXPORT const unsigned char FlexColorPickerVersionString[]; + diff --git a/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.debug.xcconfig b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.debug.xcconfig new file mode 100644 index 0000000..19922f0 --- /dev/null +++ b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.debug.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FlexColorPicker +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.modulemap b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.modulemap new file mode 100644 index 0000000..ee17040 --- /dev/null +++ b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.modulemap @@ -0,0 +1,6 @@ +framework module FlexColorPicker { + umbrella header "FlexColorPicker-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.release.xcconfig b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.release.xcconfig new file mode 100644 index 0000000..19922f0 --- /dev/null +++ b/Pods/Target Support Files/FlexColorPicker/FlexColorPicker.release.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FlexColorPicker +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-Info.plist b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-Info.plist new file mode 100644 index 0000000..c2e6784 --- /dev/null +++ b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.2.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-dummy.m b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-dummy.m new file mode 100644 index 0000000..67a74df --- /dev/null +++ b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_MBProgressHUD : NSObject +@end +@implementation PodsDummy_MBProgressHUD +@end diff --git a/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-prefix.pch b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-umbrella.h b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-umbrella.h new file mode 100644 index 0000000..8522a01 --- /dev/null +++ b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD-umbrella.h @@ -0,0 +1,17 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "MBProgressHUD.h" + +FOUNDATION_EXPORT double MBProgressHUDVersionNumber; +FOUNDATION_EXPORT const unsigned char MBProgressHUDVersionString[]; + diff --git a/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.debug.xcconfig b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.debug.xcconfig new file mode 100644 index 0000000..39dd1b9 --- /dev/null +++ b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "CoreGraphics" -framework "QuartzCore" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/MBProgressHUD +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.modulemap b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.modulemap new file mode 100644 index 0000000..dbb3f94 --- /dev/null +++ b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.modulemap @@ -0,0 +1,6 @@ +framework module MBProgressHUD { + umbrella header "MBProgressHUD-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.release.xcconfig b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.release.xcconfig new file mode 100644 index 0000000..39dd1b9 --- /dev/null +++ b/Pods/Target Support Files/MBProgressHUD/MBProgressHUD.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "CoreGraphics" -framework "QuartzCore" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/MBProgressHUD +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/MetaWear/MetaWear-Info.plist b/Pods/Target Support Files/MetaWear/MetaWear-Info.plist new file mode 100644 index 0000000..16ae820 --- /dev/null +++ b/Pods/Target Support Files/MetaWear/MetaWear-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 4.1.3 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/MetaWear/MetaWear-dummy.m b/Pods/Target Support Files/MetaWear/MetaWear-dummy.m new file mode 100644 index 0000000..99c60a6 --- /dev/null +++ b/Pods/Target Support Files/MetaWear/MetaWear-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_MetaWear : NSObject +@end +@implementation PodsDummy_MetaWear +@end diff --git a/Pods/Target Support Files/MetaWear/MetaWear-prefix.pch b/Pods/Target Support Files/MetaWear/MetaWear-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/MetaWear/MetaWear-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/MetaWear/MetaWear-umbrella.h b/Pods/Target Support Files/MetaWear/MetaWear-umbrella.h new file mode 100644 index 0000000..47e16ae --- /dev/null +++ b/Pods/Target Support Files/MetaWear/MetaWear-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double MetaWearVersionNumber; +FOUNDATION_EXPORT const unsigned char MetaWearVersionString[]; + diff --git a/Pods/Target Support Files/MetaWear/MetaWear.debug.xcconfig b/Pods/Target Support Files/MetaWear/MetaWear.debug.xcconfig new file mode 100644 index 0000000..26d1d38 --- /dev/null +++ b/Pods/Target Support Files/MetaWear/MetaWear.debug.xcconfig @@ -0,0 +1,18 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MetaWear +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts-Swift" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) $(PODS_TARGET_SRCROOT)/MetaWear/MetaWear-SDK-Cpp/src +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "BoltsSwift" -framework "CoreBluetooth" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/MetaWear +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +SWIFT_INCLUDE_PATHS = $(inherited) $(PODS_TARGET_SRCROOT)/MetaWear/MetaWear-SDK-Cpp/src +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/MetaWear/MetaWear.modulemap b/Pods/Target Support Files/MetaWear/MetaWear.modulemap new file mode 100644 index 0000000..d54986d --- /dev/null +++ b/Pods/Target Support Files/MetaWear/MetaWear.modulemap @@ -0,0 +1,6 @@ +framework module MetaWear { + umbrella header "MetaWear-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/MetaWear/MetaWear.release.xcconfig b/Pods/Target Support Files/MetaWear/MetaWear.release.xcconfig new file mode 100644 index 0000000..26d1d38 --- /dev/null +++ b/Pods/Target Support Files/MetaWear/MetaWear.release.xcconfig @@ -0,0 +1,18 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MetaWear +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts-Swift" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) $(PODS_TARGET_SRCROOT)/MetaWear/MetaWear-SDK-Cpp/src +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "BoltsSwift" -framework "CoreBluetooth" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/MetaWear +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +SWIFT_INCLUDE_PATHS = $(inherited) $(PODS_TARGET_SRCROOT)/MetaWear/MetaWear-SDK-Cpp/src +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/PRTween/PRTween-Info.plist b/Pods/Target Support Files/PRTween/PRTween-Info.plist new file mode 100644 index 0000000..434e06a --- /dev/null +++ b/Pods/Target Support Files/PRTween/PRTween-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/PRTween/PRTween-dummy.m b/Pods/Target Support Files/PRTween/PRTween-dummy.m new file mode 100644 index 0000000..44dec58 --- /dev/null +++ b/Pods/Target Support Files/PRTween/PRTween-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_PRTween : NSObject +@end +@implementation PodsDummy_PRTween +@end diff --git a/Pods/Target Support Files/PRTween/PRTween-prefix.pch b/Pods/Target Support Files/PRTween/PRTween-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/PRTween/PRTween-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/PRTween/PRTween-umbrella.h b/Pods/Target Support Files/PRTween/PRTween-umbrella.h new file mode 100644 index 0000000..2b5277c --- /dev/null +++ b/Pods/Target Support Files/PRTween/PRTween-umbrella.h @@ -0,0 +1,18 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "PRTween.h" +#import "PRTweenTimingFunctions.h" + +FOUNDATION_EXPORT double PRTweenVersionNumber; +FOUNDATION_EXPORT const unsigned char PRTweenVersionString[]; + diff --git a/Pods/Target Support Files/PRTween/PRTween.debug.xcconfig b/Pods/Target Support Files/PRTween/PRTween.debug.xcconfig new file mode 100644 index 0000000..548dc78 --- /dev/null +++ b/Pods/Target Support Files/PRTween/PRTween.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PRTween +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PRTween +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/PRTween/PRTween.modulemap b/Pods/Target Support Files/PRTween/PRTween.modulemap new file mode 100644 index 0000000..554e10a --- /dev/null +++ b/Pods/Target Support Files/PRTween/PRTween.modulemap @@ -0,0 +1,6 @@ +framework module PRTween { + umbrella header "PRTween-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/PRTween/PRTween.release.xcconfig b/Pods/Target Support Files/PRTween/PRTween.release.xcconfig new file mode 100644 index 0000000..548dc78 --- /dev/null +++ b/Pods/Target Support Files/PRTween/PRTween.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PRTween +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PRTween +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-acknowledgements.markdown b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-acknowledgements.markdown index d7afbb8..caf6fe0 100644 --- a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-acknowledgements.markdown +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-acknowledgements.markdown @@ -1,13 +1,13 @@ # Acknowledgements This application makes use of the following third party libraries: -## Bolts +## Bolts-Swift BSD License -For Bolts software +For Bolts-Swift software -Copyright (c) 2013-present, Facebook, Inc. All rights reserved. +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -34,30 +34,6 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -## FastCoding - -FastCoding - -Copyright (C) 2013 Charcoal Design - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - -3. This notice may not be removed or altered from any source distribution. - ## FlexColorPicker MIT License @@ -105,7 +81,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -## MetaWearPrivate +## MetaWear See https://www.mbientlab.com/terms/ diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-acknowledgements.plist b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-acknowledgements.plist index 7fb8e5a..946e719 100644 --- a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-acknowledgements.plist +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-acknowledgements.plist @@ -16,9 +16,9 @@ FooterText BSD License -For Bolts software +For Bolts-Swift software -Copyright (c) 2013-present, Facebook, Inc. All rights reserved. +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -47,37 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License BSD Title - Bolts - Type - PSGroupSpecifier - - - FooterText - FastCoding - -Copyright (C) 2013 Charcoal Design - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - -3. This notice may not be removed or altered from any source distribution. - License - zlib - Title - FastCoding + Bolts-Swift Type PSGroupSpecifier @@ -146,7 +116,7 @@ THE SOFTWARE.
License Commercial Title - MetaWearPrivate + MetaWear Type PSGroupSpecifier diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Debug-input-files.xcfilelist b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Debug-input-files.xcfilelist new file mode 100644 index 0000000..92fca31 --- /dev/null +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Debug-input-files.xcfilelist @@ -0,0 +1,8 @@ +${PODS_ROOT}/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks.sh +${BUILT_PRODUCTS_DIR}/Bolts-Swift/BoltsSwift.framework +${BUILT_PRODUCTS_DIR}/FlexColorPicker/FlexColorPicker.framework +${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework +${BUILT_PRODUCTS_DIR}/MetaWear/MetaWear.framework +${BUILT_PRODUCTS_DIR}/PRTween/PRTween.framework +${BUILT_PRODUCTS_DIR}/SQLite.swift/SQLite.framework +${BUILT_PRODUCTS_DIR}/StaticDataTableViewController/StaticDataTableViewController.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Debug-output-files.xcfilelist b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Debug-output-files.xcfilelist new file mode 100644 index 0000000..c97642d --- /dev/null +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Debug-output-files.xcfilelist @@ -0,0 +1,7 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BoltsSwift.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FlexColorPicker.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MetaWear.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PRTween.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SQLite.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StaticDataTableViewController.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Release-input-files.xcfilelist b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Release-input-files.xcfilelist new file mode 100644 index 0000000..92fca31 --- /dev/null +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Release-input-files.xcfilelist @@ -0,0 +1,8 @@ +${PODS_ROOT}/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks.sh +${BUILT_PRODUCTS_DIR}/Bolts-Swift/BoltsSwift.framework +${BUILT_PRODUCTS_DIR}/FlexColorPicker/FlexColorPicker.framework +${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework +${BUILT_PRODUCTS_DIR}/MetaWear/MetaWear.framework +${BUILT_PRODUCTS_DIR}/PRTween/PRTween.framework +${BUILT_PRODUCTS_DIR}/SQLite.swift/SQLite.framework +${BUILT_PRODUCTS_DIR}/StaticDataTableViewController/StaticDataTableViewController.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Release-output-files.xcfilelist b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Release-output-files.xcfilelist new file mode 100644 index 0000000..c97642d --- /dev/null +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks-Release-output-files.xcfilelist @@ -0,0 +1,7 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BoltsSwift.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FlexColorPicker.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MetaWear.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PRTween.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SQLite.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StaticDataTableViewController.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks.sh b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks.sh index 5bd14a2..d34e50e 100755 --- a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks.sh +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame-frameworks.sh @@ -176,21 +176,19 @@ code_sign_if_enabled() { } if [[ "$CONFIGURATION" == "Debug" ]]; then - install_framework "${BUILT_PRODUCTS_DIR}/Bolts/Bolts.framework" - install_framework "${BUILT_PRODUCTS_DIR}/FastCoding/FastCoding.framework" + install_framework "${BUILT_PRODUCTS_DIR}/Bolts-Swift/BoltsSwift.framework" install_framework "${BUILT_PRODUCTS_DIR}/FlexColorPicker/FlexColorPicker.framework" install_framework "${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework" - install_framework "${BUILT_PRODUCTS_DIR}/MetaWearPrivate/MetaWear.framework" + install_framework "${BUILT_PRODUCTS_DIR}/MetaWear/MetaWear.framework" install_framework "${BUILT_PRODUCTS_DIR}/PRTween/PRTween.framework" install_framework "${BUILT_PRODUCTS_DIR}/SQLite.swift/SQLite.framework" install_framework "${BUILT_PRODUCTS_DIR}/StaticDataTableViewController/StaticDataTableViewController.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then - install_framework "${BUILT_PRODUCTS_DIR}/Bolts/Bolts.framework" - install_framework "${BUILT_PRODUCTS_DIR}/FastCoding/FastCoding.framework" + install_framework "${BUILT_PRODUCTS_DIR}/Bolts-Swift/BoltsSwift.framework" install_framework "${BUILT_PRODUCTS_DIR}/FlexColorPicker/FlexColorPicker.framework" install_framework "${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework" - install_framework "${BUILT_PRODUCTS_DIR}/MetaWearPrivate/MetaWear.framework" + install_framework "${BUILT_PRODUCTS_DIR}/MetaWear/MetaWear.framework" install_framework "${BUILT_PRODUCTS_DIR}/PRTween/PRTween.framework" install_framework "${BUILT_PRODUCTS_DIR}/SQLite.swift/SQLite.framework" install_framework "${BUILT_PRODUCTS_DIR}/StaticDataTableViewController/StaticDataTableViewController.framework" diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame.debug.xcconfig b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame.debug.xcconfig index 4553ea3..3b1b5bc 100644 --- a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame.debug.xcconfig +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame.debug.xcconfig @@ -1,11 +1,11 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts" "${PODS_CONFIGURATION_BUILD_DIR}/FastCoding" "${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MetaWearPrivate" "${PODS_CONFIGURATION_BUILD_DIR}/PRTween" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift" "${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts-Swift" "${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MetaWear" "${PODS_CONFIGURATION_BUILD_DIR}/PRTween" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift" "${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts/Bolts.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FastCoding/FastCoding.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker/FlexColorPicker.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MetaWearPrivate/MetaWear.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PRTween/PRTween.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController/StaticDataTableViewController.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts-Swift/BoltsSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker/FlexColorPicker.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MetaWear/MetaWear.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PRTween/PRTween.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController/StaticDataTableViewController.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift -OTHER_LDFLAGS = $(inherited) -l"sqlite3" -framework "Bolts" -framework "CoreBluetooth" -framework "CoreData" -framework "CoreGraphics" -framework "FastCoding" -framework "FlexColorPicker" -framework "MBProgressHUD" -framework "MetaWear" -framework "PRTween" -framework "QuartzCore" -framework "SQLite" -framework "StaticDataTableViewController" +OTHER_LDFLAGS = $(inherited) -l"sqlite3" -framework "BoltsSwift" -framework "CoreBluetooth" -framework "CoreGraphics" -framework "FlexColorPicker" -framework "MBProgressHUD" -framework "MetaWear" -framework "PRTween" -framework "QuartzCore" -framework "SQLite" -framework "StaticDataTableViewController" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame.release.xcconfig b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame.release.xcconfig index 4553ea3..3b1b5bc 100644 --- a/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame.release.xcconfig +++ b/Pods/Target Support Files/Pods-MusicalCaneGame/Pods-MusicalCaneGame.release.xcconfig @@ -1,11 +1,11 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts" "${PODS_CONFIGURATION_BUILD_DIR}/FastCoding" "${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MetaWearPrivate" "${PODS_CONFIGURATION_BUILD_DIR}/PRTween" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift" "${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts-Swift" "${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MetaWear" "${PODS_CONFIGURATION_BUILD_DIR}/PRTween" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift" "${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts/Bolts.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FastCoding/FastCoding.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker/FlexColorPicker.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MetaWearPrivate/MetaWear.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PRTween/PRTween.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController/StaticDataTableViewController.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Bolts-Swift/BoltsSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FlexColorPicker/FlexColorPicker.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MetaWear/MetaWear.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PRTween/PRTween.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController/StaticDataTableViewController.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift -OTHER_LDFLAGS = $(inherited) -l"sqlite3" -framework "Bolts" -framework "CoreBluetooth" -framework "CoreData" -framework "CoreGraphics" -framework "FastCoding" -framework "FlexColorPicker" -framework "MBProgressHUD" -framework "MetaWear" -framework "PRTween" -framework "QuartzCore" -framework "SQLite" -framework "StaticDataTableViewController" +OTHER_LDFLAGS = $(inherited) -l"sqlite3" -framework "BoltsSwift" -framework "CoreBluetooth" -framework "CoreGraphics" -framework "FlexColorPicker" -framework "MBProgressHUD" -framework "MetaWear" -framework "PRTween" -framework "QuartzCore" -framework "SQLite" -framework "StaticDataTableViewController" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/Pods/Target Support Files/SQLite.swift/SQLite.swift.debug.xcconfig b/Pods/Target Support Files/SQLite.swift/SQLite.swift.debug.xcconfig new file mode 100644 index 0000000..eb9d88d --- /dev/null +++ b/Pods/Target Support Files/SQLite.swift/SQLite.swift.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -l"sqlite3" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/SQLite.swift +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +SWIFT_VERSION = 4.2 +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/SQLite.swift/SQLite.swift.release.xcconfig b/Pods/Target Support Files/SQLite.swift/SQLite.swift.release.xcconfig new file mode 100644 index 0000000..eb9d88d --- /dev/null +++ b/Pods/Target Support Files/SQLite.swift/SQLite.swift.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -l"sqlite3" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/SQLite.swift +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +SWIFT_VERSION = 4.2 +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-Info.plist b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-Info.plist new file mode 100644 index 0000000..53ada5f --- /dev/null +++ b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.5.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-dummy.m b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-dummy.m new file mode 100644 index 0000000..bb59ab9 --- /dev/null +++ b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_StaticDataTableViewController : NSObject +@end +@implementation PodsDummy_StaticDataTableViewController +@end diff --git a/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-prefix.pch b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-umbrella.h b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-umbrella.h new file mode 100644 index 0000000..b3583de --- /dev/null +++ b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController-umbrella.h @@ -0,0 +1,17 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "StaticDataTableViewController.h" + +FOUNDATION_EXPORT double StaticDataTableViewControllerVersionNumber; +FOUNDATION_EXPORT const unsigned char StaticDataTableViewControllerVersionString[]; + diff --git a/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.debug.xcconfig b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.debug.xcconfig new file mode 100644 index 0000000..0e63945 --- /dev/null +++ b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/StaticDataTableViewController +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.modulemap b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.modulemap new file mode 100644 index 0000000..f1ddbdd --- /dev/null +++ b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.modulemap @@ -0,0 +1,6 @@ +framework module StaticDataTableViewController { + umbrella header "StaticDataTableViewController-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.release.xcconfig b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.release.xcconfig new file mode 100644 index 0000000..0e63945 --- /dev/null +++ b/Pods/Target Support Files/StaticDataTableViewController/StaticDataTableViewController.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/StaticDataTableViewController +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/StaticDataTableViewController +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES From 9267a3cb6d2ff9703a4e04cd102be09e5618c7c9 Mon Sep 17 00:00:00 2001 From: Ayush Chakraborty Date: Sat, 7 Dec 2024 20:54:57 -0500 Subject: [PATCH 2/2] add back in sso button --- MusicalCaneGame/Base.lproj/Main.storyboard | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/MusicalCaneGame/Base.lproj/Main.storyboard b/MusicalCaneGame/Base.lproj/Main.storyboard index 8222209..71e9408 100755 --- a/MusicalCaneGame/Base.lproj/Main.storyboard +++ b/MusicalCaneGame/Base.lproj/Main.storyboard @@ -639,6 +639,11 @@ + + + + + @@ -647,6 +652,7 @@ + @@ -1093,28 +1099,28 @@ - + - + - + - + - + - + @@ -1127,7 +1133,7 @@ - + - +