JythonGPS HOWTO
From BUG Wiki
Contents |
JythonGPS
- Author
- Brian Ballantine
- Date
- 30 October 2007
- SDK version
- Build 248
- Virtual BUG
- Modules
- GPS
- Download
- go here
JythonGPS is the first attempt at using Python to write a BUG application. The application itself is very simple, it gets information from the GPS when the first button is pressed and displays it on the two-line LED display on the BUGbase. The purpose of this application was to lay out a path for getting BUG Apps written in Python. There are potentially many approaches, but this was the one I took. The best way to understand how everything works is to download it and take a look at the code.
NOTE: In the current release of the SDK, removing the GPS module after adding it causes errors. When the new version of the SDK is released, I will make sure this error no longer occurs and upload a new version of JythonGps. Because of this error, the GPS never "unregisters" so removing the GPS doesn't stop the Jython GpsLogger from printing the latlong as it should.
Package Structure
Under JythonGPS, there are two packages:
- jy
- This contains our Python class (JythonServiceListener.py) and our wrapper class (IJythonServiceListener.java).
- jythongps
- Here we have our Activator, which is typical in most BUG apps. Activator initializes, runs, instantiates, and uses our Python class via Jython.
- jython.jar
- The jython interpreter is all right here. Including the jar in the bundle was the easiest way to make the application work. A long term approach would be to wrap up jython.jar and any python libraries in their own bundle.
The Manifest
Include the jython jar via this line in MANIFEST.MF:
Bundle-ClassPath: .,jython.jar
Everything else should make sense. Notice the Import-Packages entry, in which I include packages for the services I'll need, IPositionProvider, IButtonEventProvider, and IStatusBarProvider.
How Does it Work?
Core Concepts
To effectively use a Python class in java, we need to write a Java wrapper interface. That interface is then implemented in Python. Using the PythonInterpreter class provided by Jython, we can create an instance of the Python class in the interpreter context, then pull it out of the interpreter and cast it as it's wrapper class. Here are two lines from the JythonGps Activator class:
interp.exec("myJythonServiceListener = JythonServiceListener(myBundleContext)");
serviceListener = (IJythonServiceListener) interp.get("myJythonServiceListener", IJythonServiceListener.class);
Activator.start
Aside from the two lines above, the Activator class does a whole lot more:
- Create a new instance of PythonInterpreter and set up PySystemState.
- Pull the import packages out of the bundle headers and add them to the PySystemState.
- This is a trick that I found here for getting your bundle classes loaded into the Jython runtime.
- Make sure to add the package that contains the wrapper interface, even if, as in this case, it's in the same place as the Python module.
- Run the Python module through the script context.
- Open the Python file through the bundle context and pass to the interpreter as a stream.
- Now an instance of the class object and the module variables are available in the interpreter context.
- Initialize the module and set up some variables
- Set the module variables for the services we will be using.
- I did it this way to make certain I was getting the correct service strings in the Python module.
- Pass the bundle context into the interpreter.
- Set the module variables for the services we will be using.
- Instantiate the Python class and pull it into the Java context.
- Cast it as the wrapper interface.
- Now use the object as you would any Java object.
- In this application, we add this ServiceListener to the context with a filter that says to call serviceChanged events only for the IPositionProvider service.
IJythonServiceListener
This is the wrapper interface or the glue, that allows us to use the python class as a java class. This interface extends ServiceListener and IButtonEventListener (maybe it should be called IJythonServiceAndButtonEventListenerOhYeah). The Python class implements this interface.
JythonServiceListener
This is where all the real BUG App Code is.
The two methods it MUST implement are:
serviceChanged(event) buttonEvent(button_event)
From here it works very similarly to Hotkey Tester and GpsLogger.
- Listens for serviceChanged events.
- When we added this service listener in the Java code, we gave it a filter that said to only give us serviceChanged events for IPositionProvider.
- In serviceChanged, we only care about REGISTERED and UNREGISTERING events for the GPS.
- When the GPS module is connected it will get a REGISTERED event.
- Attach a button listener to button 1 on the base unit.
- Ready the status bar.
- Both of these services are already available on the base unit.
- When a button is pressed, buttonEvent is called if the GPS has been initialized as described above.
- If button 1 is pressed, write out the lat and long
- If the status bar cannot be initialized (perhaps it cannot find a region big enough), it will call _log with the lat and long information. Currently _log only prints to stdout.
