<< Java Microedition where to start | Home | ETQW - Connection Lost >>

Sensor, data retrival

How to get data reading from sensor

Many of the latest mobile phones come with an in-build sensor. (So far I have only come across an accelerometer.) The most common question you'll find these days on numerous mobile development forums is "How do you access a sensor?" or "How do I get readings from a sensor?". In the next couple of lines I will show you how to get simple reading of these data on your phone.

Expected functionality:
On the key event, keyPressed() and keyReleased(), of a selected button we will retrieve data from sensor and display them on the screen of Sony Ericsson W910.

This example is based on three classes and they are:

  • SensorMidlet
  • SensorCanvas
  • SensorData
And we will start working with them in reverse order.

 

SensorData
This class will provide us with the way to communicate with the sensor. In order to establish connection with the sensor we need to provide open(String name) of javax.microedition.io.Connector class with a connection string. If you are targeting only one device, and you do know the type of the sensor built in, you may use formatted connection string as this

private static final String sensorURL= "sensor:acceleration;contextType=user;model=ST_LIS302DL;location=inside";

Simply said, we want to read acceleration with our sensor, measurement will be taken by user (the other options are "ambient"|"device"|"vehicle", however at this point I'm not clear of the exact use of them), sensor model of Sony Ericsson W910 is ST_LIS302DL and the sensor is located inside the device. However, industry will not stay with only one sensor for ever, therefore it will be much better to actually check the device for available sensors. Class like getSensorURL() as seen bellow can help us with that

private String getSensorURL(){ SensorInfo[] si = SensorManager.findSensors("acceleration", SensorInfo.CONTEXT_TYPE_USER); String URL new String(); for(int i = 0; i < si.lenght(); i++){ SensorInfo s = si[i]; URL = s.getUrl(); } return URL; }

This is not the best coding practice, as this function my return more then one acceleration sensor on the device, however as far as I know, there is only one on my SE W910 and it will do for now.

 

Now lets continue with establishing connection. This is done the traditional way, with the use of Connector class with try & catch clause and we will do it in SensorData class initialization and we will register DataListener with the SensorConnection. DataListener requires declaration of buffer size to collect amount of data. This must be greater then zero. If you like, you can set up the buffer size to one, however becuase of the sensitivity, I went for the buffer size ten.

public SensorData() { sensorURL = getSensorURL(); x = 0; y = 0; z = 0; try { sensor = (SensorConnection) Connector.open(sensorURL); sensor.setDataListener(this, 10); } catch(IOException e) { e.printStackTrace(); } }

 

Next thing we need to do is provide a way to access sensor data when we need them. Because DataListener uses asynchronous data retrieval mode we need to provide a way of synchronization. Simple getter methods for each axis coordinates with synchronized thread will do the trick.

public int getX(){ synchronized(this) {return x;} } public int getY(){ synchronized(this) { return y;} } public int getZ(){ synchronized(this) { return z;} }

Here we have

public void dataReceived(SensorConnection sensor, Data[] data, boolean isDataLost) { synchronized(this) { for(int i = 0; i < data.length; i++) { if(data[i].getChannelInfo().getName().compareTo("axis_x") == 0) { x = getAverage(data[i].getIntValues()); } else if(data[i].getChannelInfo().getName().compareTo("axis_y") == 0) { y = getAverage(data[i].getIntValues()); } else if(data[i].getChannelInfo().getName().compareTo("axis_z") == 0) { z = getAverage(data[i].getIntValues()); } } } }

which makes use of getAverage(int[] values) method. I hope I do not need to explain this.

 

Last method in SensorData class is closeConnection() method. The method will allow us to close SensorConnection just before the midlet is destroyed. In this case, I have decided to leave the sensor connection open for the whole midlet run and closed only when the midlet is about to be destroyed.

public void closeConnection() { try { sensor.close(); } catch(IOException e) { e.printStackTrace(); } }

The whole SensorData class can be downloaded on the end of the post.

 

SensorCanvas
As we need to capture keyEvent we can not use Screen class with its subclasses Alert, Form, List, TextBox. The canvas functionality will consist of event delivery methods ( keyPressed() and keyReleased() ) for chosen button, and also a drawing board to display collected sensor coordinates. When SensorCanvas class is initialized, an instance of SensorData class is received with already open sensor connection.

public SensorCanvas(SensorData sData) { sd = sData; }

 

The canvas paint(Graphics g) method is very simple. We will get width and height of the screen on currently used device. Set the background colour to white and fill the rectangle from staring point top left-corner (0, 0) to bottom-right corner (width, height) with background colour. In the middle of the screen we will display message "Press the key!" and wait for user action.

public void paint(Graphics g) { int w = getWidth(); int h = getHeight(); g.setColor(0xffffff); g.fillRect(0, 0, w, h); int fh = g.getFont().getHeight(); int y = h / 2 - fh * 2; g.setColor(0x000000); g.drawString(mMessage, w / 2, y, Graphics.HCENTER | Graphics.BOTTOM); y += fh; //More code will be added here }

The event delivery methods are very simple as you can see.

protected void keyPressed(int keyCode) { mMessage = "KeyPressed()"; if(getGameAction(keyCode) == GAME_A) { mKeyCode = keyCode; repaint(); } } protected void keyReleased(int keyCode) { mMessage = "keyReleased()"; if(getGameAction(keyCode) == GAME_A) { mKeyCode = keyCode; repaint(); } }

Once selected key is pressed or released, in my case game button A, they will check for the source. If desired button triggered the action, the repaint() method is executed including the if statement.

public void paint(Graphics g) { //Previous section of paint() method code here if(mKeyCode != 0) { xCor = sd.getX(); yCor = sd.getY(); zCor = sd.getZ(); g.drawString("X coordinate: " + xCor, w / 2, y, Graphics.HCENTER | Graphics.BOTTOM); y += fh; g.drawString("Y coordinate: " + yCor, w / 2, y, Graphics.HCENTER | Graphics.BOTTOM); y += fh; g.drawString("Z coordiante: " + zCor, w / 2, y, Graphics.HCENTER | Graphics.BOTTOM); } }

The whole SensorCanvas class can be downloaded on the end of the post.

 

SensorMidlet is not different from any other you may have already seen. Explanation in simple bullet points:

  • declaring mCanvas
  • declaring exitCommand
  • declaring and initializing SensorData
once midlet started:
  • get current display
  • initialize canvas with SensorCanvas and provide instance of SensorData object
  • initialize exitCommand
  • add the command to canvas
  • add command listener to canvas
  • display current canvas
Once midlet gets command from exitCommand listener it will first attempt to close connection with the sensor and after it destroy itself.

 

Source Files
SensorMidlet.java
SensorCanvas.java
SensorData.java

Working JAR file can be downloaded from attachments bellow this post.




Add a comment Send a TrackBack