2
\$\begingroup\$

I am creating a Mac OS X application. This application will connect to a MetaWear sensor over ble, and log the accelerometer and gyro data (I want to store 30 samples for each, per second). Here are some details on my env and the framework of choice, as outlined in my cocoapod file:

platform :osx, '10.12.6'
pod 'MetaWear', '~> 2.9'

My appDelegate.swift class looks as follows:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!


    func applicationDidFinishLaunching(_ aNotification: Notification) {
        BluetoothWorker().startConection();
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // nothing for now
    }

}

As seen above, when the app starts, I call a startConnection() method in my Bluetooth class, which is defined as follows:

import Foundation

import MetaWear

class BluetoothWorker : NSObject {

    var totalAccelSample : Int = 0;
    var totalGyroSample : Int = 0;

    let acceleroLogger = AcceleroDataLogger();
    let gyroLogger = GyroDataLogger();
    let formatter = DateFormatter();
    let manager = MBLMetaWearManager.shared();

    override init() {
        super.init();
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS";
    }

    func startConection() {

        manager.startScanForMetaWears() {array in

            let device : array.last!;

            // stop the scan
            self.manager.stopScan();
            print("### stopping scan");

            device.connectAsync().success() { _ in
                    print("### connected to our sensor");

                    DispatchQueue.global().async {
                        self.startRecordingGyro(device: device);
                    }
                    DispatchQueue.global().async {
                        self.startRecordingAccelerometer(device: device);
                    }

                }.failure() { error in
                    print("## unable to connect to the sensor", error);
                    exit(-1);
            }
        }

    }

    func startRecordingGyro(device : MBLMetaWear) {
            print("### recording gyro");
            device.gyro?.sampleFrequency = 30;
            device.gyro?.dataReadyEvent.startNotificationsAsync(handler: { (obj, error) in
                if let obj = obj {
                    self.totalGyroSample += 1;
                    let toWrite = "\(obj.x)," + "\(obj.y)," + "\(obj.z)," + self.formatter.string(from: Date()) + ",\(self.totalGyroSample)";
                    DispatchQueue.global().async {
                        self.gyroLogger.writeGyroData(stretchSenseEntry: toWrite);
                    }
                }
            });
    }

    func startRecordingAccelerometer(device : MBLMetaWear) {
        print("### recording accelerometer");
        device.accelerometer?.sampleFrequency = 30;
        device.accelerometer?.dataReadyEvent.startNotificationsAsync(handler: { (obj, error) in
            if let obj = obj {
                self.totalAccelSample += 1;
                let toWrite = "\(obj.x)," + "\(obj.y)," + "\(obj.z)," + self.self.formatter.string(from: Date()) + ",\(self.totalAccelSample)";
                DispatchQueue.global().async {
                    self.acceleroLogger.writeAcceleroData(stretchSenseEntry: toWrite);
                }
            }
        });
    }

}

My logger classes are called by the BluetoothWorker to store data. Currently, you see two, GyroDataLogger() and AcceleroDataLogger(). Soon, I will consolidate these two into one, but here is the code for the former:

import Foundation

class GyroDataLogger: NSObject {

    var counter:Int = 0;
    var file: FileHandle!;

    override init() {
        super.init();
        do {
            let fileNameUrl = URL(string: FileManager.default.currentDirectoryPath + "/gyro.log");
            file = try FileHandle(forWritingTo: fileNameUrl!);
            file.write("x,y,z,time,sample\n".data(using: String.Encoding.utf8, allowLossyConversion: false)!);
        } catch {
            print(error.localizedDescription);
            exit(EXIT_FAILURE);
        }
    }

    func writeGyroData(stretchSenseEntry : String) {
        file.seekToEndOfFile();
        let toWrite = stretchSenseEntry + "\n";
        file.write(toWrite.data(using: String.Encoding.utf8, allowLossyConversion: false)!);
    }

    deinit {
        file.closeFile();
    }

}

Questions:

  1. My goal is to be able to capture sensor readings as fast as possible, for any number of features I decide to take. Currently, I am hoping to read the gyro and the accelerometer. Here is the documentation I am using to make this happen: dox. Am I using DispatchQueue.global().async correctly to make sure that the startRecordingGyro and startRecordingAccelerometer methods can execute at the same time?
  2. Am I being efficient (speed of data write) with my file storing. i.e GyroDataLogger?
  3. Is my use of DispatchQueue.global().async efficient and correct?
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.