Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Sunday, February 9, 2014

LEGO Mindstorms RCX 2.0 in 2014...

I still have a LEGO Mindstorms RCX 2.0 from 2003, and once more the question was: Is it still possible to program the device?

The Windows XP computer that I had used in 2010 (with difficulty, see post from back then) is no more. A brief search only indicated that there's no driver for Windows Vista/7/8, let alone 64 bit. BUT: I always preferred using the RCX with LeJOS, i.e. Java, instead of the Windows based GUI. Then it turns out that Linux actually contains a `linuxusbtower` kernel driver in most distributions. So overall, this sounded easier than ever?!

After installing a current Ubuntu release, the LEGO USB tower was indeed recognized, creating `/dev/usb/legousbtower1` whenever plugged in. But LeJOS 2.1.0 just didn't work, giving various communication errors in the `firmdl` program. I tried to compile the `linuxusbtower` kernel driver from the 2.1.0 sources, but could not find an easy way to get the required kernel source includes.

The solution was to use the LeJOS 3.0.0 "release candidate" (from 2006). It communicated with the Ubuntu-provided `legousbtower` kernel driver just fine. Only quirks:

  • `lejos/bin/*` scripts needed to be `chmod`ed as executable
  • `lejos/bin/lejos` needed the same "export LD_LIBRARY_PATH" and "java -cp .." for the `*.so` shared library that was already in `lejos/bin/lejosjc`
These changes might be included in the latest CVS checkout, but the `*.tgz` download has the advantage that for example `firmdl` can be invoked right away without having to build anything.

Used Eclipse by creating a plain Java project, then removing the default JRE links and instead adding the `lejos/lib/*.jar` files to the build path.
So with Linux and Java, it's possible to use a 10+ year old LEGO brick, and it works just fine.
Compared to an Arduino, it is actually still quite attractive as an into to computer fun for teenagers: In one box, with batteries, you get a motor controller, sensor reader, and simple display and "beeper". With an Arduino, you'd have to add a battery box, speaker, motor shield, LCD, plus put that all into an enclosure.

Thursday, July 5, 2012

RIGblaster plug & play needs USB-2

Tried to communicate with a RIGblaster plug & play via Java RXTX.
The Rigblaster is essentially a USB-to-serial converter. All functioned fine on a new Windows 7 computer with 64 bit Java, until suddenly it didn't. The RXTX code hung somewhere in its CommPortIdentifier class that is used to open a port.

Reason turned out the type of USB port. This computer happens to have USB-2 as well as newer USB-3 ports. With USB-2 all is fine, with USB-3 the RXTX library hangs.

Wednesday, July 4, 2012

Eclipse E4 Selections, Events, Context Variables

Eclipse 4.2 includes the new "E4" APIs which offer different ways of communication between portions of your Eclipse application.
The Lars Vogel article http://www.vogella.com/articles/Eclipse4Services/article.html nicely lists these, and here are some comments from trying them out.

Selections

In Eclipse 3.x, you used the ISelectionProvider:

ISelectionProvider selections = null;
selections.setSelection(new StructuredSelection(selected_item));

Obtaining the selection provider could be circuitous, and the selection had to be published as an ISelection, typically a StructuredSelection.

On the receiving end, you needed to register a listener to the selection provider and unpack the ISelection.
In Eclipse E4, there is @Inject magic at play that can be difficult to debug, but the resulting code is sure nice:

// In a "GUI creation" routine invoked via @PostConstruct,
// arguments are injected because the @Inject is implied.
// To get an ESelectionService injected into other method,
// a specific @Inject would be required.
@PostConstruct
public void createControls(final Composite parent,
    final ESelectionService selections)
{
    // Create GUI...
    // ... monitor for example selection of list.
    MyModelObject my_selected_object = ...;
    // Publish any selectd model object or array of model objects "as is".
    // No need to wrap into StructuredSelection:
    selections.setSelection(my_selected_object);
});

To receive such a selection in another piece of E4 code:

// E4 will invoke this whenever the active selection changes.
// If the active selection is instanceof MyModelObject, it will be provided.
// Otherwise, null will be sent.
@Inject
public void handleChangedSelection(
    @Optional
    @Named(IServiceConstants.ACTIVE_SELECTION)
    final MyModelObject selected)
{
    // No need to unpack a StructuredSelection.
    // May only have to check for null
    System.out.println("Received changed selection " + selected);
}

If your selection listener happens to only receive null arguments, the reason is likely that the selected object does not match the type that you want to receive. To debug this, change the argument of your selection receiver from MyModelObject to just Object and check the type of the received object.
When porting existing code, you may by accident still publish a StructuredSelection that wraps your MyModelObject class. The E4 framework will not unwrap a StructuredSelection. Just publish and receive the exact class that you want to transfer!

Context Variables

There is only one global selection mechanism. If you want to pass updates on various model items between E4 components, you can use context variables.
Publishing anything into a context variable is as easy as publishing a selection, but note that you can now name the item that you put into the context. This allows you to publish different types of information under different names, effectively having access to multiple selection services.
You can either use a string or a class reference:

@Inject
public void methodThatPublishesContextVariable(final MWindow window)
{
    MyModelObject my_selected_object = ...;

    final IEclipseContext context = window.getContext();
    context.declareModifiable("my_item");
    context.set("my_item", my_selected_object);
}

Receiving the item updates is very similar to receiving the selection:

// E4 will invoke this whenever the named context variable changes.
@Inject
public void handleChangedItem(
    @Optional
    @Named("my_item")
    final MyModelObject item)
{
    // May have to check for null
    System.out.println("Received changed item " + item);
}

It is important to remember that the context is hierarchical!
In the publishing code it is tempting to directly ask E4 to inject the context like this instead of going via the MWindow as shown before:

@Inject
public void methodThatPublishesContextVariable(final IEclipseContext context)
{
    ...
    context.set("my_item", ...);
}

This will not work as expected! The context that your part gets injected will be the context of your part. You will then publish the context variable for "my_item" within that local context, and updates are not received by other parts. By instead asking for the window to be injected and publishing to the window's context, all parts within that window will receive updates:

@Inject
public void methodThatPublishesContextVariable(final MWindow window)
{
    final IEclipseContext context = window.getContext();
    ...
    context.set("my_item", my_selected_object);
}

If you want all windows of your application to receive updates, you can even use the application's context:

@Inject
public void methodThatPublishesContextVariable(final MApplication app)
{
    final IEclipseContext context = app.getContext();
    ...
    context.set("my_item", my_selected_object);
}

The scoped, hierarchical nature of the context variable mechanism therefore allows you to control who receives the updates: The same part, all parts in the window, or everything in the application.

Event Broker

Finally, the IEventBroker provides a lower level mechanism to post and receive events. When posting events, you can decide to simply post them in a fire-and-forget mode, or send them and wait for the receivers to handle them:

class MyClass
{
    // Receive event broker.
    // Could also fetch in code via
    // IEclipseContext.get(IEventBroker.class)
    @Inject
    private IEventBroker event_broker;
    
    void codeThatSendsEvents()
    {
        MyModelObject my_object = ...;
        event_broker.post("my_object", my_object);
    }

The 'post()' shown here is the fire-and-forget way. Use 'send()' to wait for receivers to handle the event.
To receive events for the topic "my_object" that carry data of type MyModelObject, use the following:

@Inject
public void receiveEvent(
    @Optional
    @UIEventTopic("my_object") final MyModelObject item)
{
    System.out.println("Received " + item);
}

When replacing @UIEventTopic with @EventTopic, events will be received on some event handling thread. The annotation @UIEventTopic asserts that events are received on the user interface thread, which is useful if your event receiver intends to make UI modifications, for example display the event in SWT widgets.




Friday, June 15, 2012

Eclipse Plugins with Native Code for Multiple Platforms

Eclipse plugins can contain native code. Since the native code is specific to a certain architecture, this should probably be put into a fragment that is then added to the 'main' plugin depending on the architecture.

Such fragments can support multiple platforms, for example Linux on both 32 and 64 bit CPUs, by adding something like this to the MANIFEST.MF:

Eclipse-PlatformFilter: (& (osgi.os=linux) (| (osgi.arch=x86)(osgi.arch=x86_64)))
Bundle-NativeCode: 
 lib/linux/x86/mylib.so;    osname=linux; processor=x86,
 lib/linux/x86_64/mylib.so; osname=linux; processor=x86_64

On Linux, the correct library for either CPU type will be now available.Excellent!

However, when combining such plugins into a feature-based product, a problem arises. Assume you have a fragment for windows, one for Linux, one for OS X. When you add the fragments to the product's feature, you must again specify their architecture:

   plugin
         id="org.mylib.linux"
         os="linux"
         arch="x86"
         ...
If you don't specify the os and arch in the feature, the build will fail: Eclipse will try to include your plugin on both Windows and Linux, but then complain that the "linux" plugin doesn't work on Windows and vice versa.

If you do specify the os and arch, however, you can only list one arch, even though our linux fragment would work on both x86 and x86_64.

The solution is to list the same fragment again in the fragment.xml with the other os and arch settings:

   plugin
         id="org.mylib.linux"
         os="linux"
         arch="x86_64"
         ...

Note that you may have to do this directly in the feature.xml. The feature editor's Plug-Ins tab doesn't support adding an already included plugin multiple times, but once you did add it in the feature.xml, you can view and edit it in there.

Wednesday, February 29, 2012

Eclipse JFace 'VIRTUAL' TreeViewer basically requires TreeColumnLayout?

When switching a TreeViewer from an ITreeContentProvider to a 'VIRTUAL' TreeViewer with ILazyTreeContentProvider, the tree display initially appeared blank. The items in the tree would only become visible after waiting a little, or by doing some window operations that result in a refresh of the tree. This happened especially on Mac OS X.

After looking closer, it became obvious that the one and only column of the tree had a nearly zero width. Note the arrow in the image that shows the column separator:




The issue seems to be that a non-VIRTUAL TreeViewer knows all its items right away and can size the tree columns appropriately. When swtiching to a VIRTUAL TreeViewer, the items are updated as needed, and the column refresh can lag.

Early "fixes" involved forcing a refresh after setting the TreeViewer input:

tree.setRedraw(false);
tree_viewer.setInput(config);
tree_viewer.refresh();
tree.setRedraw(true);

or

tree_viewer.expandAll();

But the best workaround seems to be to use a TreeColumnLayout that always auto-sizes the one and only column:


// Note that the TreeViewer needs to be the only widget
// under the parent widget. If necessary, add Composite
// to wrap the TreeViewer
final TreeColumnLayout layout = new TreeColumnLayout();
parent.setLayout(layout);
final TreeViewer v = new TreeViewer(shell, SWT.VIRTUAL | SWT.BORDER);
v.setLabelProvider(new LabelProvider());

Friday, February 3, 2012

Avoid Soft Links in Eclipse Headless build - or ant in general?

Ran into a really strange problem.
As a result of a headless Eclipse product build, I usually get an abc.app for Mac OS X.
But this time around I got an abc.app for Mac OS X that "worked", but the program icon was wrong. In addition, there was an Eclipse.app directory that's mostly empty.
Products for other architectures (Linux, Windows) looked OK.

Apparently, the build process had first put the Eclipse.app in place, tried to assign the icon etc., and then renamed it to the actual product name abc.app, but something failed in the process. The Eclipse.app partially remained in place, and there was no icon.

Solution: I had recently changed the build directory to /tmp. On Mac OS X, /tmp is a soft link (symbolic link) to /private/var. Either the Eclipse headless build or maybe ant in general has problems with soft links. After using a "real" directory path without any soft links as the build directory, things were fine again.

Friday, September 9, 2011

JDBC 'commit' even for SELECT

You probably knew this, but a 'commit' can even be necessary for SELECT calls that don't change any data.

After calling JDBC Connection.setAutoCommit(true)), every JDBC call, be it SELECT, INSERT, UPDATE, DELETE starts a transaction that needs to be ended with a commit (or rollback).

This might be obvious for a sequence of INSERT or UPDATE calls that change data, and you want a final commit() to perform an atomic update.

With a SELECT, the update is necessary to avoid the following situation:
  1. Calling SELECT to fetch something. That starts a Transaction!
  2. Now somebody else changes the data.
  3. You call SELECT again to get the 'latest', but since you're still in the original Transaction, you get the same old data as in step 1.
If you have other code that changes the data and happens to call commit() before you reach step 3, all will look OK, but to be sure that you end the original reading transaction and always get the 'latest' data in a later read, it has to be done like this:
  1. SELECT, commit()
  2. Now the data might change.
  3. If you later need to fetch the 'latest', again SELECT and commit()

Thursday, March 10, 2011

"Portable" Eclipse Projects

When you create a new Eclipse 'Plug-in' project, its initial configuration will lock to your current JRE and compiler settings.
When you then share that project with other people, they will see compiler errors because you may have used Java 1.6_19 on Linux while they use Java 1.6_20 on Windows.

To make your project more portable, do this:

  1. In the Package Explorer, right-click on your Plug-in Project and select "Properties"
  2. Under "Java Build Path", select tab "Libraries", item "JRE System Library", button "Edit". It should default to a specific "Execution environment" like "JavaSE1-6 (MacOS X 1.6.0 System). Change that to "Workspace default JRE", meaning: Use whatever the developer has configured in her workspace.
  3. Under "Java Compiler", by default "Enable project specific settings" will be checked. Uncheck that, meaning: Use the compiler settings that the developer has selected in her workspace.
  4. When you now switch to the Navigator view, you should find that the ".settings" directory that previously contained project-specific compiler settings is now empty. You can delete it.
After these steps, developers on other operating systems with slightly different java versions will have fever problems when they try to use your Plug-in source. Your MANIFEST.MF can still require a certain execution environment, so you are not loosing much control.

Friday, February 11, 2011

Java Audio, FreeTTS "LINE UNAVAILABLE" Error

A program based on FreeTTS, the free text-to-speech engine for Java, was getting occasional errors
"LINE UNAVAILABLE: Format is ..."
The reason was later found in the KDE desktop: Its configuration panel has options to keep the audio device open for some time after playing beeps or other desktop sounds. The default seemed to be rather high at 60 seconds. But even after changing that to only 2 seconds, the FreeTTS library still needs to compete with some occasional other users of the audio devices.
Turns out there is no Java Exception or other mechanism to detect this error that occurs inside the FreeTTS library. All you get is the message on System.out, so there is no good way to react programatically.

Workaround: Configure the FreeTTS audio player to attempt accessing the audio device more than once until it succeeds. In this example, a short delay of 0.1 seconds is used to not miss an opportunity to grab the audio device; we keep trying for 30 seconds:
System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.openFailDelayMs", "100");
System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.totalOpenFailDelayMs", "30000");
If the audio device is permanently used by another program, there is of course no way to get access. Under Linux, this command will display the ID of the process that is currently holding the audio device, so you can then try to get rid of the offending program:
  /sbin/fuser /dev/dsp

Tuesday, January 18, 2011

Eclipse Build Path Problem After Mac OS X Java Update

In early January 2011, I received a Mac OS X Software Update that included Java changes.
This was on a Mac that had been upgraded to Snow Leopard, so older Java setups were still present, but this update must have removed older JVMs and JDKs.

As a result, Eclipse builds would fail with this error:
The container 'JRE System Library [J2SE-1.5]' references non existing library '/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Classes/laf.jar'
In general, the OS X Java setup changed from using
/System/Library/Frameworks/Java.VM.framework/Versions/...
to using a path like
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

After going to Eclipse/Preferences/Java/Installed JREs and "Add..."ing a new JVM that uses the above path with ".../JavaVirtualMachines/..." all is fine again. You might have to look for the full path to that .../Home in a terminal window and copy/paste it into the Eclipse preference dialog, because the "Browse" button in the dialog might only show the 1.6.0.jdk as a package, not as a subdirectory into which you can drill down.

Next issue: You might not have a src.jar in that JDK to be able to view the Java sources, so you cannot view the source code for String, Map, ... and the other standard Java classes. That's because the default JDK is really more like a JRE.

After downloading the Java Development package from the Apple Developer Connection, something like javadeveloper_10.6_10m3261.dmg, you get a new JDK in

/Library/Java/JavaVirtualMachines/1.6.0_22-b04-307.jdk

and that one has a Content/Home/src.jar.
Note that the JDK that you install yourself, the one that includes the sources, is under /Library/Java/... while the Java stuff that comes with the OS is under /System/Library/Java/...

Eclipse should automatically detect the src.jar in the JDK that you install.

Note on finding the Java Development package as of August 2011:
  • http://developer.apple.com/
  • Member Center
  • Dev Centers: Mac
  • Resources
  • Mac OS X Developer Downloads
  • Java
  • Java for Mac OS X ... Developer ...