Please note as of Wednesday, August 15th, 2018 this wiki has been set to read only. If you are a TI Employee and require Edit ability please contact x0211426 from the company directory.

GUI Composer/Logging Graph Data

From Texas Instruments Wiki
Jump to: navigation, search

Logging Graph Data in GUI Composer

Overview

GUI Composer version 6 introduces data logging functionality. GUI Composer application developers can provide functionality that stores data sent to application in log files. GUI Composer provides Javascript APIs that allows end user to specify log files on her/his local file system. We will use these APIs to demonstrate how to implement logging of the data that a Line Graph widget displays.

In this example you are a GUI Composer application developer. We assume that you are familiar with Code Composer Studio, GUI Composer and writing Javascript code. You will create and run a Code Composer Studio program that continually modifies the values of an integer array. You will create a GUI Composer application that displays the array data in a Line Graph Widget. You will add widgets to the application to enable the end user to control the logging process. The user will be able to specify the file where the data will be stored; to turn on and off the logging at any time, as well as to reset the file, so the next logged data will be added to the beginning of the file.

The GUI Composer project can be downloaded from GraphLogging.zip and imported to GUI Composer(Requires CCSv6 and higher).

The Code Composer Studio project for a F28069 Piccolo device can be downloaded from LogDemo.zip and imported to Code Composer Studio(Requires CCSv6 and higher).


Create a Code Composer program that changes the value of an array in a loop.

  • Start Code Compose Studio.
  • Create a new project.
  • Add an integer array “ABC” with 100 elements and initialize it with some values.
  • Make the program continuously change the values of the array elements in an infinite loop.

Here is an example of a program that does that:

#define ARRAY_SIZE 100
int ABC[ARRAY_SIZE];
 
void initArray() {
	int i = 0;
	for( i = 0; i < ARRAY_SIZE; ++i) {
		ABC[i] = i;
	};
}
void shiftArray() {
	static int delta = 0;
	int i = 0;
	for( i = 0; i < ARRAY_SIZE; ++i) {
		ABC[i] = (delta + i) % ARRAY_SIZE;
	};
	++delta;
}
void main() {
	initArray();
	while(1) {
		shiftArray();
	}
}
  • Create a target configuration file compatible with the project and link it to the project.
  • Debug the project.
  • Verify the array is updating when stepping through the code.


Allow memory to be read while the target is running.

Steps in this section are only necessary for targets that do not allow non-intrusive access to memory. E.g. All C2000 and Tiva devices are capable of accessing memory through emulator without halting the CPU. By default when the target is running the target memory is not accessible from the debugger. Here we will change a debugger property that will allow that access. This change will allow the graph widget to update while the target is running.

  • Terminate the debug session.
  • Open the launch configuration dialog.
  • Select the launch configuration that was debugged.
  • Switch to the “Target” tab.
  • Select “Auto Run and Launch Options” in the left pane of the window.
  • Check the option “Halt the target before any debugger access…” option.
  • Save the launch configuration.


Create a GUI composer app with a Line Graph widget in it.

  • From the CC App Center install GUI Composer and Javascript Development tools - Code Composer Studio Add-ons (if not already installed).
  • Open GUI Composer.
  • Create a new GUI Composer project – name it GraphLogging.
  • Drag and drop a Line Graph widget to the working area of GUI Composer.
  • Rename the graph widget id in the property page on the right pane to widget_graph.
  • Bind Series 0 Value of the graph to the program array ABC.
  • Debug the program.
  • Run the target.
  • Switch the app to Preview mode. The graph should show new target data every second.
  • Exit the preview mode.


Add logging controls widgets to the app.

We need to add additional controls to the app to allow the user to specify the file where the data will be logged, to stop and start the logging, as well as reset logging to the beginning of the file. Here is the app with the new widgets:

Logging Graph app.png

  • From the GUI Composer pallet drag and drop two label widgets: Logging Enabled and Path.
  • Drag and drop a CheckBox widget and set its widget id to widget_log_enabled from the Widget section of the property page on the right.
  • Drag and drop a TextBox widget and set its widget it to widget_path.
  • Drag and drop a Button widget with label Log to File....
  • Select the Events section in the property page on the right and type in onBrowse() for onclick event.
  • Drag and drop a Button widget with label Reset.
  • Select the Events section in the property page on the right and type in onReset() for onclick event.


Add the javascript code - app.js

Now we will add all Javascript code necessary to make the example work. We will add different functions as we need them and explain their purpose. The whole Javascript file is listed at the end of the document. You can copy and paste it from there to your project.

Using the watch event listener subscribe to changes in the graph series when the application has loaded and initialized.

require(["dojo/ready"], function(ready){
     ready(function(){
		 dijit.byId('widget_graph').watch('series0', function( prop, newValue, oldValue) {
			 logData( newValue, false);
		 });
     });
});

We will add two variables that store the file path and the state of the Logged Enabled check box.

var FI = undefined;
var Logged = false;

The function logData() will use the GUI Composer function TI.CSVFile().save() to save the data if the right conditions are met: the user has specified the file, the Logging Enabled check box is checked. It displays an error message if the write operation failed. We will add a parameter reset that will indicate if we want to start writing from the beginning of the file or not. When the graph data changes we pass false in that parameter, when the user selects the Reset button we will pass true.

function logData( data, reset) {
	if( !reset && !isLogging())
		return;
	var file = getFileName();
	if( !file)
		return;
	var callback = function( fileInfo, errorInfo) {
		if( errorInfo) {
			$TI.helper.showError( "Error Logging.", errorInfo.message);
		}
	}
	var options = getOptions();
	if( !reset) {
		options.append = true;
		options.addCRAfter = true;
	}
	new TI.CSVFile().save( data, FI, options, callback);
}


We need to add the helper functions used there before the function logData():

function isLogging() {
	return dijit.byId('widget_log_enabled').get('checked');
}
 
function getFileName() {
	return dijit.byId('widget_path').get('value');
}
 
function getOptions() {
	return {
		clientLocation : 'auto'
	}
}


When the user selects the Log to File ... button we will call the API TI.CSVFile().browseAndSave() to browse and save the data to file. We also remember in the variable FI the file path information the user has chosen in the browse dialog:

function onBrowse() {
	var data = getData();
	var callback = function( fileInfo, errorInfo) {
		if( errorInfo) {
			$TI.helper.showError( "Save as...", errorInfo.message);
		}
		else {
			FI = fileInfo;
			updateFields();
		}
	};
	var options = getOptions();
	options.addCRAfter = true;
	new TI.CSVFile().browseAndSave( data, FI, options, callback);
}


Above the function onBrowse() we add the helper functions used there.

function getData() {
	return dijit.byId( 'widget_graph').get('series0');
}
 
 
function setFileName( name) {
	dijit.byId( 'widget_path').set('value',name);
}
 
function updateFileName() {
	var name = '';
	if( FI && FI.localPath) {
		name = FI.localPath;
	}
	setFileName(name);
}
 
function updateFields() {
	updateFileName();
}

When the user selects the Reset button we only need to call logData() with reset parameter set to true.

function onReset() {
	logData( "", true);
}

And that is all.


Here is the full content of the file app.js

/*
 * This file is provided for custom JavaScript logic that your HTML files might need.
 * GUI Composer includes this JavaScript file by default within HTML pages authored in GUI Composer.
 */
require(["dojo/ready"], function(ready){
     ready(function(){
		 dijit.byId('widget_graph').watch('series0', function( prop, newValue, oldValue) {
			 logData( newValue, false);
		 });
     });
});
 
var FI = undefined;
var Logged = false;
 
function isLogging() {
	return dijit.byId('widget_log_enabled').get('checked');
}
 
function getFileName() {
	return dijit.byId('widget_path').get('value');
}
 
function getOptions() {
	return {
		clientLocation : 'auto'
	}
}
 
function logData( data, reset) {
	if( !reset && !isLogging())
		return;
	var file = getFileName();
	if( !file)
		return;
	var callback = function( fileInfo, errorInfo) {
		if( errorInfo) {
			$TI.helper.showError( "Error Logging.", errorInfo.message);
		}
	}
	var options = getOptions();
	if( !reset) {
		options.append = true;
		options.addCRAfter = true;
	}
	new TI.CSVFile().save( data, FI, options, callback);
}
 
function getData() {
	return dijit.byId( 'widget_graph').get('series0');
}
 
function setFileName( name) {
	dijit.byId( 'widget_path').set('value',name);
}
 
function updateFileName() {
	var name = '';
	if( FI && FI.localPath) {
		name = FI.localPath;
	}
	setFileName(name);
}
 
function updateFields() {
	updateFileName();
}
 
function onBrowse() {
	var data = getData();
	var callback = function( fileInfo, errorInfo) {
		if( errorInfo) {
			$TI.helper.showError( "Save as...", errorInfo.message);
		}
		else {
			FI = fileInfo;
			updateFields();
		}
	};
	var options = getOptions();
	options.addCRAfter = true;
	new TI.CSVFile().browseAndSave( data, FI, options, callback);
}
 
function onReset() {
	logData( "", true);
}


Testing the example

  • Run the program.
  • Switch the GUI Composer application to preview mode – you will see the graph data is changing.
  • Select Log to File... button and specify the name a of text file that will store the logged data.
  • Turn on the check box Logging Enabled – once the file is specified and the logging is enabled each second a new data will be added to the file.
  • Let it run for 10 to 20 seconds.
  • Turn off the check box Logging Enabled.
  • Open the file specific in a text editor and you will see all logged data.
  • You can select the Reset button and check that all logged data has been deleted.