Best way to programming this app?

Hi!

First of all, i am new in Eclipse and Monkey C programming language. But i have good background programming in C#.

I am currently working with a vivoactive 3 watch given up by Garmin to my PhD research. My aim is to progrmming an app which be able to get the watch sensor signals to externally processing it. Concretelly i need the accelerometre and the hearth rate signals. I have read the Garmin´s official website programmer guide to get some background on Monkey C. But i would like to ask about what will be the best way to get these signals and send it from the watch to an smartphone. I would like to run the app in background, so i would not need to programming a GUI.

Someone can help me on "where to begin":

I would like to know what is the best App Type for my project, if there exist some open source/example apps to get the signal and communicate the watch and finally how i can store data on the watch.

For example, i am having problems creating a .xml file on resources folder, to use JSON as in Garmins example. When i compile the code, i get errors.:

Garmin example:

<resources>
<jsonData id="jsonDictionary">{"key":"value", "3":"three", "three":3}</jsonData>
<jsonData id="jsonArray">[1,2,3,4,5,6]</jsonData>
<jsonData id="jsonMix">[1,{"1":"one"},["a","b","c"]]</jsonData>
<jsonData id="jsonPrimitive">5</jsonData>
<jsonData id="jsonFile" filename="data.json"/>
</resources>


Errors:

BUILD: ERROR: Problem validating a resource file: Premature end of file.
BUILD: com.garmin.monkeybrains.resourcecompiler.ResourceException: Problem validating a resource file: Premature end of file.
BUILD: at com.garmin.monkeybrains.resourcecompiler.DocumentParser.validateResourceFile(DocumentParser.java:285)
BUILD: at com.garmin.monkeybrains.resourcecompiler.DocumentParser.addJungleResources(DocumentParser.java:399)
BUILD: at com.garmin.monkeybrains.Project.addProjectResources(Project.java:163)
BUILD: at com.garmin.monkeybrains.ProjectBuilder.addCIQProjectFiles(ProjectBuilder.java:210)
BUILD: at com.garmin.monkeybrains.Monkeybrains.runPRGCompiler(Monkeybrains.java:1229)
BUILD: at com.garmin.monkeybrains.Monkeybrains.compileApplication(Monkeybrains.java:1024)
BUILD: at com.garmin.monkeybrains.Monkeybrains.run(Monkeybrains.java:2315)
BUILD: at com.garmin.monkeybrains.Monkeybrains.simpleMain(Monkeybrains.java:254)
BUILD: at com.garmin.monkeybrains.Monkeybrains.simpleMain(Monkeybrains.java:236)
BUILD: at com.garmin.monkeybrains.Monkeybrains.main(Monkeybrains.java:283)
BUILD: Caused by: org.xml.sax.SAXParseException; systemId: file:/D:/1.-GIT/4.%20Tesis/Desarrollo-Tesis/Desarrollos/03-Pruebas%20Recursos/resources/jsonData.xml; lineNumber: 1; columnNumber: 1; Premature end of file.
BUILD: at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1471)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:1013)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:534)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.StreamValidatorHelper.validate(StreamValidatorHelper.java:176)
BUILD: at java.xml/com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(ValidatorImpl.java:115)
BUILD: at java.xml/javax.xml.validation.Validator.validate(Validator.java:124)
BUILD: at com.garmin.monkeybrains.resourcecompiler.DocumentParser.validateResourceFile(DocumentParser.java:281)
BUILD: ... 9 more
BUILD: usage: monkeyc [-a <arg>] [-d <arg>] [-e] [--Eno-invalid-symbol] [-f <arg>] [-g]
BUILD: [-h] [-i <arg>] [-m <arg>] [-o <arg>] [-p <arg>] [-r] [-s <arg>] [-t] [-u
BUILD: <arg>] [-v] [-w] [-x <arg>] [-y <arg>] [-z <arg>]
BUILD: -a,--apidb <arg> API import file
BUILD: -d,--device <arg> Target device
BUILD: -e,--package-app Create an application package.
BUILD: --Eno-invalid-symbolDo not error when a symbol is found to be invalid
BUILD: -f,--jungles <arg> Jungle files
BUILD: -g,--debug Print debug output
BUILD: -h,--help Prints help information
BUILD: -i,--import-dbg <arg> Import api.debug.xml
BUILD: -m,--manifest <arg> Manifest file
BUILD: -o,--output <arg> Output file to create
BUILD: -p,--project-info <arg>projectInfo.xml file to use when compiling
BUILD: -r,--release Strip debug information
BUILD: -s,--sdk-version <arg> SDK version to target
BUILD: -t,--unit-test Enables compilation of unit tests
BUILD: -u,--devices <arg> devices.xml file to use when compiling
BUILD: -v,--version Prints the compiler version
BUILD: -w,--warn Show compiler warnings
BUILD: -x,--excludes <arg> Add annotations to the exclude list
BUILD: -y,--private-key <arg> Private key to sign builds with
BUILD: -z,--rez <arg> Resource file

Hope you can help me.

Regards!

  • I wouldn't count on it, as its not on the phone that long.  If there's no internet connection of the phone, it won't even sync the .fit to the phone.

  • The devices are synced by BT, I suppose if there is not connection, the .fit file will be stored in the watch and synced on next time the devices get connection. 

    Do you know how long the file is stored in the phone? Or if it can be find programmatically from Android app? 

  • Hi again!

    I have been checking the Pitch Counter example and i have simulate data in the CIQ simulator. When i have save the session and open the data on Subime, i have seen that the .fit file is not plain text.

    0e10 2a08 0000 0000 2e46 4954 0000 4000
    0000 0009 0304 8c04 0486 0704 8608 1407
    0102 8402 0284 0502 8406 0284 0001 0000
    0000 0000 229f f437 ffff ffff 0000 0000
    0000 0000 0000 0000 0000 0000 0000 0000
    0100 0f27 ffff ffff 0441 0000 3100 0200
    0284 0101 0201 6400 ff42 0000 1500 0efd
    0486 0304 8602 0284 0502 8406 0284 0702
    ....

    Any idea of how i can decrypt this data?

    Thanks!

  • This SDK is to use in Eclipse with ANT?

    I would need to use it in Android Studio. My aim is to decode the .Fit file in a mobile app or to find the best way to send the watch sensor data to the mobile without lose data. 

  • The fit sdk defines how you can read a fit file and get it's content.

  • Hi Travis!

    For the session example you pasted me above, wich kind of app did you use? I am wondering about which is the best place in the app to start the session, becouse in the pitch counter sample, the session appears in a class called process, which is called from the view. But in your first example (get low and high frecuency data) you have a Behaviour Delegate.

  • Hi Again!

    I have finally programmed the app based on the PitchCounter example, using the session object. I am running it from the CIQ Simulator. And simulating data from Simulation/Fit Data/SImulate Data. 

    As you can see in the picture below, i am correctly getting data and printing in te console. In this case is accelerometre X axis data and Hearth rate beat intervals every second.

    When i stop the simulation and i save the session from simulator (Simulation/FIT Data/Save FIT Session), i get a .FIT file, but this file has not the data i am trying to record in it (accelerometer and Heart Rate). When i open it, i see the next:

    I get dummy data from latitude, longitude, altitude, distance, speed, grade and timestamp. But the accelerometer and heart rate data has not be recorded. Why this is happening?

    If i analize the code, i am not saying specifically to save accelerometer and hearth rate data on the file when a new sample arrives. I paste my code to see if you can check it and do you find any error.

    using Toybox.WatchUi;
    using Toybox.Sensor;
    using Toybox.Math;
    using Toybox.SensorLogging;
    using Toybox.ActivityRecording;
    using Toybox.System;
    
    class SacarDatosSession {
    
        var mPauseCount = 0;
        var mPauseTime = 0;
        var mSkipSample = 25;
        var mPitchCount = 0;
        var acc_X = [0];
        var acc_Y = [0];
        var acc_Z = [0];
        var acc_Roll = [0];
        var acc_Pitch = [0];
        var acc_Power = [0];
        
        var frecuenciaCardiaca = [0];
    
        var mLogger;
        var mSession = null;
        
        // Constructor
        function initialize() {
        
            if(mSession==null){
            
    	        try {
    	        
    	            mLogger = new SensorLogging.SensorLogger({
    	            				:enableAccelerometer => true});
    	            mSession = ActivityRecording.createSession({
    	            	:name=>"DatosReloj", 
    	            	:sport=>ActivityRecording.SPORT_GENERIC,
    	            	:subSport => ActivityRecording.SUB_SPORT_GENERIC, 
    	            	:sensorLogger => mLogger
    	           	});
    	            	            
    	        }
    	        catch(e) {
    	            System.println(e.getErrorMessage());
    	        }
    		}else{
        	
        		mSession.stop();
                mSession.save();
                mSession = null;
        	}
    
        }
    
        // Callback to receive accel data
        function sensores_callback(sensorData) {
        
        	// miramos si estamos pudiendo acceder a los datos de los sensores
    		var accelerometerData = sensorData.accelerometerData;
    	 	var heartRateData = sensorData.heartRateData;
        	
        	if(accelerometerData)
        	{
        	    // guardamos todos los datos del acelerometro
    	        acc_X = sensorData.accelerometerData.x;
    	        acc_Y = sensorData.accelerometerData.y;
    	        acc_Z = sensorData.accelerometerData.z;
    	        acc_Pitch = accelerometerData.pitch;
    		    acc_Roll = accelerometerData.roll;
    		    acc_Power = accelerometerData.power;
    	        // procesadoDatosAcelerometro(); // aqui se procesarian los datos del acelerometro
        	}
            System.println(sensorData.accelerometerData.x);
            System.println(sensorData.heartRateData.heartBeatIntervals);
            
        }
    
    
        function onStart() {
    
    		// creamos el diccionario de opciones para inicializar los sensores        
    		var options = {
    	    	:period => 1,           // invoke the callback once a second
    	    	:accelerometer => {
    	    		:enabled => true,
    	    		:sampleRate => 25,  // 25 samples/second
    	    		:includePower => true,
    	    		:includePitch => true,
    	    		:includeRoll => true,
    	    	},
    	        :heartBeatIntervals => {
    	        	:enabled => true
    	        }
    	    };
    
            try {
                Sensor.registerSensorDataListener(method(:sensores_callback), options);
                mSession.start();
            }
            catch(e) {
                System.println(e.getErrorMessage());
            }
        }
    
    
        function onStop() {
            Sensor.unregisterSensorDataListener();
            mSession.save();
            mSession = null;
            mSession.stop();
        }
    
        // Return current pitch count
        function getCount() {
            return mPitchCount;
        }
    
        // Return current pitch count
        function getSamples() {
            return mLogger.getStats().sampleCount;
        }
    
        // Return current pitch count
        function getPeriod() {
            return mLogger.getStats().samplePeriod;
        }
    
        
    }
    

    I am also having issues with the Logger objet, when i execute the next code lines i do not recive anything.

    mLogger.getStats().sampleCount;
    mLogger.getStats().samplePeriod;

    Hope you can help me.

    Regards!

  • Have you tested with the pitch counter sample to verify that you can see the data in the FIT file? I'd start there. If it works with that app, then you've done something wrong and we'll have to isolate it. If you don't see the data, then maybe we need to figure out why.

  • Hi, i did the same that i explained on this answear with both examples, PitchCounter and my app. And this is what i see. What i mean is that the data does not have sense to me.

    hope you can help me

    Hi Again!

    I have finally programmed the app based on the PitchCounter example, using the session object. I am running it from the CIQ Simulator. And simulating data from Simulation/Fit Data/SImulate Data. 

    As you can see in the picture below, i am correctly getting data and printing in te console. In this case is accelerometre X axis data and Hearth rate beat intervals every second.

    When i stop the simulation and i save the session from simulator (Simulation/FIT Data/Save FIT Session), i get a .FIT file, but this file has not the data i am trying to record in it (accelerometer and Heart Rate). When i open it, i see the next:

    I get dummy data from latitude, longitude, altitude, distance, speed, grade and timestamp. But the accelerometer and heart rate data has not be recorded. Why this is happening?

    If i analize the code, i am not saying specifically to save accelerometer and hearth rate data on the file when a new sample arrives. I paste my code to see if you can check it and do you find any error.

    using Toybox.WatchUi;
    using Toybox.Sensor;
    using Toybox.Math;
    using Toybox.SensorLogging;
    using Toybox.ActivityRecording;
    using Toybox.System;
    
    class SacarDatosSession {
    
        var mPauseCount = 0;
        var mPauseTime = 0;
        var mSkipSample = 25;
        var mPitchCount = 0;
        var acc_X = [0];
        var acc_Y = [0];
        var acc_Z = [0];
        var acc_Roll = [0];
        var acc_Pitch = [0];
        var acc_Power = [0];
        
        var frecuenciaCardiaca = [0];
    
        var mLogger;
        var mSession = null;
        
        // Constructor
        function initialize() {
        
            if(mSession==null){
            
    	        try {
    	        
    	            mLogger = new SensorLogging.SensorLogger({
    	            				:enableAccelerometer => true});
    	            mSession = ActivityRecording.createSession({
    	            	:name=>"DatosReloj", 
    	            	:sport=>ActivityRecording.SPORT_GENERIC,
    	            	:subSport => ActivityRecording.SUB_SPORT_GENERIC, 
    	            	:sensorLogger => mLogger
    	           	});
    	            	            
    	        }
    	        catch(e) {
    	            System.println(e.getErrorMessage());
    	        }
    		}else{
        	
        		mSession.stop();
                mSession.save();
                mSession = null;
        	}
    
        }
    
        // Callback to receive accel data
        function sensores_callback(sensorData) {
        
        	// miramos si estamos pudiendo acceder a los datos de los sensores
    		var accelerometerData = sensorData.accelerometerData;
    	 	var heartRateData = sensorData.heartRateData;
        	
        	if(accelerometerData)
        	{
        	    // guardamos todos los datos del acelerometro
    	        acc_X = sensorData.accelerometerData.x;
    	        acc_Y = sensorData.accelerometerData.y;
    	        acc_Z = sensorData.accelerometerData.z;
    	        acc_Pitch = accelerometerData.pitch;
    		    acc_Roll = accelerometerData.roll;
    		    acc_Power = accelerometerData.power;
    	        // procesadoDatosAcelerometro(); // aqui se procesarian los datos del acelerometro
        	}
            System.println(sensorData.accelerometerData.x);
            System.println(sensorData.heartRateData.heartBeatIntervals);
            
        }
    
    
        function onStart() {
    
    		// creamos el diccionario de opciones para inicializar los sensores        
    		var options = {
    	    	:period => 1,           // invoke the callback once a second
    	    	:accelerometer => {
    	    		:enabled => true,
    	    		:sampleRate => 25,  // 25 samples/second
    	    		:includePower => true,
    	    		:includePitch => true,
    	    		:includeRoll => true,
    	    	},
    	        :heartBeatIntervals => {
    	        	:enabled => true
    	        }
    	    };
    
            try {
                Sensor.registerSensorDataListener(method(:sensores_callback), options);
                mSession.start();
            }
            catch(e) {
                System.println(e.getErrorMessage());
            }
        }
    
    
        function onStop() {
            Sensor.unregisterSensorDataListener();
            mSession.save();
            mSession = null;
            mSession.stop();
        }
    
        // Return current pitch count
        function getCount() {
            return mPitchCount;
        }
    
        // Return current pitch count
        function getSamples() {
            return mLogger.getStats().sampleCount;
        }
    
        // Return current pitch count
        function getPeriod() {
            return mLogger.getStats().samplePeriod;
        }
    
        
    }
    

    I am also having issues with the Logger objet, when i execute the next code lines i do not recive anything.

    mLogger.getStats().sampleCount;
    mLogger.getStats().samplePeriod;

    Hope you can help me.

    Regards!