User:Jeangareau/sandbox

=Overview=

In order to import a workout from the Timex Run Trainer device, the user selects the Workouts menu and clicks on Manage Imports, which shows a list of devices to import from templates/workouts/modals/choose_device.html, as shown on Figure 1. Each button is linked to ${request.path}?source=source_name, which is translated (how???) to a Javascript import page. For instance, clicking on the Timex button shows templates/workouts/modals/import_timex.html.

The Javascript import page uses the  MMF.TimexDeviceControl object, itself based on the generic  MMF.DeviceControl device control interface, to retrieve workout data. Those objects are implemented in public/js/mmf/import/MMFDeviceControl.js and TimexDeviceControl.js.

The device control interface loads and directly interacts with the plug-in.

The plug-in is a Win32 module developed in C++ that implements NPAPI, a cross-browser plug-in API. The plug-in directly accesses the Timex watch's data via the computer's USB port. The plug-in must be downloaded and installed once in order to be loadable by a browser.

=General Architecture= The components of the Timex Import are the following:
 * Browser Plug-in
 * Device Control API
 * Javascript Import Page

Design
The plug-in is developed with Firebreath under Microsoft Visual Studio Express 2010. Firebreath provides a framework to build a NPAPI-compliant dynamic-link library (DLL) in C++ and utility classes to build Javascript objects.

Because the plug-in is a native Windows component, it must be downloaded and installed on a Windows-based PC running XP, Vista or 7. Firebreath provides a template to generate an .MSI installer file, which is customized with MapMyFitness branding. Users must download and install the plug-in on their computer once. Afterwards, it will automatically be loaded and accessed by the MMF.DeviceControl.

The plug-in itself uses a Timex-provided static-link library to access the Timex Run Trainer watch, retrieve the workout data and pass them back as Javascript objects to the MMF.DeviceControl interface, which passes it back to the Javascript import page.

Implementation
The plug-in, as generated by FireBreath, includes multiple Visual Studio projects as part of the solution. The only project that is of interest is MMFTimex878 as it implements the Plug-in API (the other projects implement core browser integration modules).

The plug-in uses a Timex-provided static-link library to access the Timex watch. The Timex library is blocking: a read operation does not immediately return, but instead returns when it is completed, which may take a few seconds. In order to keep the browser responsive, calls to the Timex library are implemented in background threads to ensure that calls to the plug-in are non-blocking (i.e. immediately return).

The wrapping Javascript (as implemented in MMF.DeviceControl) is expected to poll the plug-in (e.g. every 500ms) to determine whether an operation has completed or not, when calling one of the following plug-in functions (described  below):



MMF.DeviceControl
The MapMyFitness Device Control API is implemented in MMF.DeviceControl ( MMFDeviceControl.js ). It's a generic Javascript object that retrieves workout data by loading a plug-in and calling its API. An import page instantiates a MMF.DeviceControl-derived object and uses generic methods to access the device's data.

In order to provide the browser a non-blocking access to the device, MMF.DeviceControl invokes the plug-in and polls it to determine when operations are completed. Once an operation completes, it notifies the import page via a listener. A listener is an object with explicit (but optional) methods to be called when specific operations complete and is described below.

MMF.TimexDeviceControl
A specific device is accessed by creating a new Javascript object derived from MMF.DeviceControl. The Timex Run Trainer is implemented in TimexDeviceControl.js as follows:

Javascript Import Page
The import page is implemented in import_timex.html and contains a great deal of Javascript along some HTML code to display a table (a list of workouts) and a few buttons (Start Import, Stop Import, etc).

is first called to instantiate a MMF.TimexDeviceControl object known as the "controller". The plug-in is then loaded, a listener is registered and the device look-up is initiated, by calling the controller's,   and   respectively.

When the listener's  is called, the import page makes sure there is indeed a device connected (otherwise it shows an error), and calls , which invokes the controller's.

The listener's  is eventually called, which invokes. This function creates an array of activities and calls  to query the status of these activities (New, Ignored, etc.) and to display them in the table.

When the Start Import button is clicked,  is called. Selected and unselected activities are stored in two arrays respectively, each activity identified via. A back-end query is then sent to set the status of the unselected activities as "ignored". Then the process of storing each activity is started by repeatedly calling, which calls the controller's.

When the listener's  is called,   sends a back-end query to store the workout by passing the JSON representation of the workout. On success, the workout is marked as Imported in the list (or Failed on error). The scenario is repeated for each selected activity in the list.

The user can then import more workouts or close the window.

=Javascript Objects Reference=

Plug-in API
In that project, the files MMFTimex878API.h/.cpp implement a Javascript object of the same name that implements the key Javascript methods and objects below. The FireBreath framework translates Javascript calls to internal C++ calls within the plug-in.

Device Access
Starts looking for a Timex device asynchronously, using the Timex library to actually detect the device. Once a device is detected, it builds a MMFDevice object that is returned when  is called.

Returns "true" if the device look-up is completed, otherwise "" is returned to indicate that the asynchronous lookup is still taking place.

Returns a MMFDevice object if a device is connected, or null if there's no device connected.

Asynchronously terminates the connection to the device.

Workout Data
Starts reading a workouts summary asynchronously and builds an array of [[#MMFActivity|MMFActivity] objects accordingly.

Returns "true" when the  and/or   is completed, otherwise "" is returned to indicate that it is still taking place.

Return the an array of zero, once or more MMFActivity objects.

Starts reading a specific workout asynchronously. Once  returns true,   can be called to retrieve the data.

Returns a JSON-formatted string describing the last workout read. The format is described in ???.

Version
Returns the plug-in version e.g. "1.0.0.0"

MMF.DeviceControl
Initializes MMF.DeviceControl with the plug-in id, its MIME time and its ActiveX ProgID.

Loads the plug by writing an object referencing the plug-in in the DOM. This is turns instructs the browser to load the actual plug-in. The  exception is raised if the plug-in is not loaded. The  exception is raised if the id is invalid.

Registers a listener with the following (optional) functions:



Initiates the device look-up. Once the look-up completes, the listener's  is called back. Its parameter  refers to a MMFDevice object if the device has been found, or null if there's no device connected.

Initiates the activities (workouts summary) download from the device. Once completed, the listener's  is called and the   parameter contains an array with zero, one or more MMFActivity objects.

Initiates the activities (workouts summary) download from the device. Once completed, the listener's  is called and the   object is a JSON-formatted string of the workout.

Closes the physical connection with the device.

Returns the plug-in id. This is the same parameter passed to.

Returns the plug-in version e.g. "1.0.0.0". This is the string returned by the plug-in's  function.

MMFDevice
MMFDevice describes a device.

Properties

Device id, OEM-specific

Part number, OEM-specific

Human-readable name

Methods

Returns displayName

MMFActivity
MMFActivity is a workout summary.

Properties

Returns one of the following attributes:


 * "activityName" returns the type of activity e.g. "Running"
 * "startTime" is the workout start time e.g. "2011-12-24 01:42:32 PM"
 * "duration" is the duration e.g. "01:20:34"

Returns the activity name by calling.

=New Plug-in Development=

Support for a new device requires the following steps:


 * Develop a new plug-in via Firebreath and implement the Plug-in API, thereby making it compatible with Javascript objects derived from MMF.DeviceControl. This minimizes the effort while developing new import pages because they can rely on the model established by MMF.DeviceControl.


 * Create a Javascript object derived from MMF.DeviceControl that references the plug-in, such as MMF.TimexDeviceControl. The parameters when invoking   as those provided by  Firebreath. MMF.DeviceControl itself should not be changed.


 * Develop an import page that instantiates that Javascript object and interacts with it using the MMF.DeviceControl interface. The data can be passed to the back-end in JSON format (just as the Timex import page does).