Communication with Pinguino via Bluetooth

I bought a BlueSMIRF Bluetooth module a few weeks ago, and this weekend I’ve finally had some time to put it in action 🙂

Connecting the BlueSMIRF module is really easy. The BlueSMIRF module has 6 pins: CTS-I, VCC, GND, TX-0, RX-1 and RTS-0. You have to connect CTS-I to RTS-0, connect VCC to the supply voltage and GND to ground. The TX-0 pin is connected to the RX pin of the microprocessor, while the RX-1 pin is connected to the TX pin of the microprocessor. On the PIC18F4455 these are pins 26 and 25 (pinguino pins 9 and 8). s

CTS-I  O----------------
VCC    O--5V           |
GND    O--0V (gnd)     |
TX-0   O-- to RX PIC   |
RX-1   O-- to TX PIC   |
RTS-0  O----------------

As explained in a previous post, I am using a Pinguino board, so the code should work on Arduino as well without needing too many modifications. This is the code I used for writing some text:

#define PIC18F4550
char incomingByte = 'K';	// for incoming serial data

void setup() {
  Serial.begin(115200);
}

void loop() {
	// send data only when you receive a C character
	if (Serial.available() > 0) {
		// read the incoming byte:
		incomingByte = Serial.read();
		if (incomingByte == 'C') {
			Serial.print("I received: ");
			Serial.print(incomingByte, DEC);
		}
	}
}
In the setup routine I connect to the serial port at 115200 bauds. The bluetooth module is just used as a regular serial cable, so no fancy tricks are necessary.
On my Ubuntu laptop, I had to do the following to get things running:
  • first connect your Bluetooth dongle to the BlueSMIRF (mine appeared as FireFLY-719A)
  • sudo hcitool scan #so we know the MAC address of the FireFLY
  • rfcomm connect 0 00:06:66:03:72:9A #substitute with your BlueSMIRF’s MAC address
  • sudo gtkterm -p /dev/rfcomm0 -s 115200 #start gtkterm to read/write to the serial port

Of course we don’t want to interact through gtkterm with our microcontroller. I wanted to employ Processing, but this gave some additional difficulties in my setup. In Processing, Serial.list() is used to list all available serial ports. The Bluetooth serial port /dev/rfcomm0 does not appear in the list though. A dirty hack to solve the issue is symlinking /dev/ttyS0 to /dev/rfcomm0:

sudo rm /dev/ttyS0
sudo ln -s /dev/rfcomm0 /dev/ttyS0

If anyone knows a better way to solve the issue, please mention so in the comments! This is the Processing code:

import processing.serial.*;

Serial myPort;                // Create object from Serial class

void setup()
{
  size(200, 200);
  myPort = new Serial(this, Serial.list()[0], 115200);  //the first port in the list is /dev/ttyS0 which we symlinked to /dev/rfcomm0
}

void draw()
{
  while (myPort.available() > 0) {                      //if something was received via serial port
    String inBuffer = myPort.readString();
    print(inBuffer);
  }
}

void keyPressed() {
  print(key);
  myPort.write(key);
}

void stop() {
  myPort.stop();
}

February 22, 2010 at 6:12 pm 3 comments

Synergy rocks

Just used the open-source software Synergy to share my mouse and keyboard between three laptops with different Operating Systems (Vista, Ubuntu, Xubuntu)!

You’ll have to start Synergy on all computers (on Ubuntu / Xubuntu I installed the GUI QuickSynergy from the software management). The computer with the keyboard and mouse you want to share will be the server, the other the clients. On the server, enter the position of the different screens (laptop1 is on the left of laptop2 etc.). Click start on all Synergy’s and now the desktop will extend to the other screens!

January 9, 2010 at 12:09 pm Leave a comment

Using Dwengo board as a Pinguino

The Pinguino project is a relatively new project that tries to build an Arduino-like project with a PIC processor. The project comes with a nice and simple IDE and a bootloader so programs can be placed on the PIC very easy.  I found the Dwengo board I own is compatible with the Tiny-4550 Pinguino board, so it is possible to use the Pinguino IDE and bootloader with the Dwengo board. 

Here are the steps I followed on my Ubuntu (Karmic) machine to get things fired up:

  • Install wxPython as explained here
  • Download the latest Pinguino IDE from the hackinglab dowload index. Extract the archive. Run the IDE by running the pinguinobetax.py Python script from the terminal. Put sudo before it to run it with administrator rights, because otherwise you’ll get a ”Could not change device” error! The IDE looks like this:

  • With the PIC18F4550 we need the second version of the bootloader (see Pinguino tutorial site). It can be dowloaded here. To put the bootloader on your PIC, I used xwisp, which is a Windows program (I ran it in a Virtualbox virtual machine).
  • Once the bootloader is on your PIC, connect your board via a USB cable to your PC. Hold the reset button and the “up” button on your board, then release the reset button. The bootloader program knows you want to place a program on it now.
  • Open up the Pinguino IDE and type e.g. this program in it:
// Testing input with Pinguino
// jean-pierre MANDON 2008
// modified kr3l for DWENGO
#define PIC18F4550
void setup() 
{
pinMode(0,INPUT);         //button
pinMode(21,OUTPUT);    //led
}
void loop() 
{
if (digitalread(0)) digitalWrite(21,HIGH);
else digitalWrite(21,LOW);
}
The pin numbers used here are as in the Tiny-4550 schematic:
so pin 21 as used in the program is actually pin 19 of the PIC processor.
  • press the compile button, then the “put program on pinguino” button. The program starts running after a few seconds. If you press the center button one of the leds will go off.

I think the Pinguino project is a really cool initiative and I hope they keep working on it. More experiments will be conducted soon!

December 31, 2009 at 3:35 pm 1 comment

Use Google Docs for generating live reports on your Ruby scripts

I have to transfer and convert a lot of files this week, and in order not to loose track, I created a spreadsheet that summarizes which files are transferred and converted. Because it was a pain to keep the spreadsheet up to date I wrote a Ruby script that monitors the files written and writes the results back to a Google docs spreadsheet.

To monitor the files I use the so-called backtick quote, which reads the output of a command to a variable:

res = `cd /home/thefolder;ls -l`
res.each_line do |line|
  cols = line.split(' ')
  if cols.length<9  #probably a header row
    next
  end
  if File.file?('/home/thefolder/'+cols[8])
    #the file exists, your code here
    #my code writes to a hash called items
  end
end
To write the results back I used gimite’s google-spreadsheet-ruby gem (http://github.com/gimite/google-spreadsheet-ruby) that makes it trivially easy to connect to a Google spreadsheet (just follow the “how to use” on the first page).
def dump_to_google(items)
  session = GoogleSpreadsheet.login("user@gmail.com", password)
  ws = session.spreadsheet_by_key("YOURKEYYOURKEYYOURKEY").worksheets[0]
  col = 1 
  row = 1
  ws[row,1] = 'ID'
  ws[row,2] = 'Filename'
  ...
  row+=1
  items.each do |id,itm|
    ws[row,1] = id
    ws[row,2] = itm[:filename]

     ...
    row+=1
  end
  ws.save()
end

The end result is pretty cool, a spreadsheet that is updated every minute (or whatever interval you decide). You can also create graphs that are updated automatically with the new data:




December 10, 2009 at 9:13 pm Leave a comment

Extract a keyframe from a video with FFMpeg

If you want to extract a particular frame from a video, you can use the following ffmpeg command:

ffmpeg -i INPUTPATH -vframes 1 -ss TIMESTAMP -f image2 -vcodec mjpeg OUTPUTPATH.jpg

where TIMESTAMP is in the format hh:mm:ss.ff

If you have the frame number instead of the timestamp, you can use the following Ruby script to convert the frame number to the timestamp (for a framerate of 25fps) – there’s probably a better way for formatting a number to have two digits though :-):

def self.profile_thumbnail(frame_nr = nil)
#calculate timestamp
begin
  if frame_nr.nil?
    framenr = 25*60*2
  else
    framenr = frame_nr.to_i
  end

rescue
  framenr = 25*60*2
end

uur = (framenr/(60*60*25))
min = ((framenr-uur*60*60*25)/(60*25))
sec = ((framenr-uur*60*60*25-min*60*25)/25)
frame = ((framenr-uur*60*60*25-min*60*25-sec*25))
uur_s = uur.to_s
if uur<10
  uur_s = '0'+uur_s
end
min_s = min.to_s
if min<10
  min_s = '0'+min_s
end
sec_s = sec.to_s
if sec<10
  sec_s='0'+sec_s
end
frame_s = frame.to_s
if frame<10
  frame_s = '00'+frame_s
elsif frame<100
  frame_s = '0'+frame_s
end

stamp = uur_s+':'+min_s+':'+sec_s+'.'+frame_s
return  ' -vframes 1 -ss '+stamp+' -f image2 -vcodec mjpeg '

end

December 3, 2009 at 9:07 pm Leave a comment

Using Hudson for a Ruby project

This post explains how to let Hudson automatically run your unit tests / rspec tests upon pushing code to your git repository.

Installing and running Hudson is easy:

wget http://hudson-ci.org/latest/hudson.war
nohup java -jar hudson.war --httpPort=7080 --prefix=/hudson >> "hudson.log" 2>&1 &

If you browse to localhost:7080/hudson you’ll be greeted by the user interface of Hudson. I’ve explicitly set the port to 7080 because the default port (8080) was already used by tomcat in my case. Now we’ll add some plugins. In Hudson’s user interface click on “manage Hudson” and click on “add plugins”. Install the following plugins: git, ruby, ruby metrics, rake. Click on “restart Hudson when no jobs are running” after the plugins are installed.

We’ll use rake for defining our test tasks. Make a rake file (named Rakefile) in your project root folder.

require ‘rake’
require 'rake/testtask'
require 'rake/packagetask'
require 'rake'
require 'rake/testtask'
require 'rake/packagetask'
require 'spec/version'
require 'spec/rake/spectask'
require 'rcov'
gem 'ci_reporter'
require 'ci/reporter/rake/test_unit'	#http://juretta.com/log/2008/11/11/hudson_test_drive_part_1_rails/
require 'ci/reporter/rake/rspec'
desc 'do unit tests'
Rake::TestTask.new(:test) do |t|
    t.libs << 'lib'
    t.pattern = 'test/test_*.rb'
    t.verbose = true
end

namespace :spec do
  desc "do rspec tests and test coverage"
  Spec::Rake::SpecTask.new('rcov') do |t|
    t.spec_files = FileList['spec/**/*_spec.rb']
    t.spec_opts = ['--format html:results/spec_results.html']
    t.warning = true
    t.rcov = true
    t.rcov_dir = 'coverage'
    t.rcov_opts = ['--exclude', "kernel,load-diff-lcs\.rb,instance_exec\.rb,lib/spec.rb,lib/spec/runner.rb,^spec/*,bin/spec,examples,/gems,/Library/Ruby,\.autotest,#{ENV['GEM_HOME']}",                  '-I', 'lib/']
end

end
Take a look at the following sites for more info on the Rakefile:
Now create a new Hudson job (freestyle project) that checks out the code from your repository. Add two build steps of the type “execute shell command”:
  1. GEM_HOME=/opt/myproject/shared/gems rake ci:setup:testunit test CI_REPORTS=results
  2. GEM_HOME=/opt/myproject/shared/gems SPEC_OPTS=”–format html:resultsspec/spec_results.html” rake ci:setup:rspec spec:rcov CI_REPORTS=resultsspec

The GEM_HOME=… part is only necessary if you install your gems locally in you project folder instead of system-wide. In the first job we call the take task ci:setup:testunit which is defined in the ci_reporter gem. This gem will create Hudson-compatible reports out of the reports generated by test unit or rspec. Next we call the rake test task which will actually run the unit tests. We also pass a variable CI_REPORTS which tells ci_reporter where to create the reports.

The second job first runs the ci:setup:rspec task which again prepares ci_reporter. Then we call spec:rcov which will run the rspec tests and create the coverage reports. Note the SPEC_OPTS variable in which we tell rspec to create an html report (which will be converted to xml files by ci_reporter).

Now check the post build actions “publish JUnit reports” and “publish coverage reports”, save the Hudson project and build it!

If all went well, Hudson will create some nice reports out of the test and coverage reports:

Because sometimes you want all the detail you can get, you might want to add links to the original (html) test and coverage reports in the description of your project. Click “Change description” and enter something like:

<a href="http://localhost:7080/hudson/job/myproject/ws/resultsspec/spec_results.html" target="_blanc">detailed spec results</a><br>

<a href="http://localhost:7080/hudson/job/myproject/ws/coverage/index.html" target="_blanc">detailed code coverage report</a>

Et voila! You now have a butler running your tests and creating nice reports as soon as you commit code to your repository!

December 3, 2009 at 8:44 pm Leave a comment

Check in Java web app if user is logged in in Rails web app

I have a Rails application where users can log in and do stuff. For one of the actions a user can perform, I actually use a Java web application integrated in the Rails application. Because I don’t want a malicious user that is not logged in to the application to surf directly to the Java application, I need a system where my Java application is only accessible for users logged in to the Rails application. I used a Servlet Filter that contacts the Rails application in the background and asks if the user is logged in. Only then is the user allowed to proceed.

First I built an a controller in Rails with an action that checks if the user is logged in. In my application this is available at the url localhost:3000/session/check.

class SessionController < ApplicationController

def check

if session[‘user’].nil?

logged_in = false

else

logged_in = true

end

render :text => logged_in.to_s #just write true or false to the output

end

end

package be.vrt.medialab.filters;

Now I want my Java web application to first request the Rails session check and when it returns false it should redirect to the login page instead of serving the Java servlets. I used a Java servlet filter for this job. I created the filter in a separate project, here is the source code:

package be.vrt.medialab.filters;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.net.MalformedURLException;

import java.util.ResourceBundle;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletContext;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.Cookie;

import javax.servlet.http.HttpServletRequest;

public class RailsAuthentication implements Filter {

FilterConfig filterConfig = null;

private ResourceBundle resources;

public RailsAuthentication() {

resources = ResourceBundle.getBundle(“config”);

}

public boolean getRailsResponse(String urlString,String cookie) {

// Open a URL connection.

java.net.URL url;

try {

System.out.println(“urlString=”+urlString);

url = new java.net.URL( urlString );

final java.net.URLConnection uconn = url.openConnection( );

if ( !(uconn instanceof java.net.HttpURLConnection) )

throw new java.lang.IllegalArgumentException(

“URL protocol must be HTTP.” );

final java.net.HttpURLConnection conn =

(java.net.HttpURLConnection)uconn;

// Set up a request.

conn.setConnectTimeout( 10000 ); // 10 sec

conn.setReadTimeout( 10000 ); // 10 sec

conn.setInstanceFollowRedirects( true );

conn.setRequestProperty( “User-agent”, “spider” );

conn.setRequestProperty(“Cookie”, “_ifip_rails_session=”+cookie+“;”);

// Send the request.

conn.connect( );

BufferedReader in = new BufferedReader( new InputStreamReader((InputStream) conn.getContent( )));

String inputLine;

inputLine = in.readLine(); // Process each line.

System.out.println(“rails returned: “+inputLine);

conn.disconnect( );

if (inputLine.equals(“true”)) {

//authentication successful: user is logged in

System.out.println(“authentication successful!”);

return true;

} else {

//authentication failed: user is not logged in

System.out.println(“authentication failed!”);

return false;

}

} catch (Exception e) {

e.printStackTrace();

}

return false;

}

public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException,ServletException {

String railsCheck =resources.getString(“RailsCheck”);

String invalidUrl=resources.getString(“InvalidUrl”);

HttpServletRequest request = (HttpServletRequest) req;

Cookie[] cookies = request.getCookies();

String rails_session_id = null;

for(int i=0;i<cookies.length;i++) {

Cookie cookie = cookies[i];

if (cookie.getName().equals(“_ifip_rails_session”)) {

rails_session_id = cookie.getValue();

}

}

if (rails_session_id == null) {

//authentication fails

System.out.println(“Autentication fails, no rails session id!”);

} else {

System.out.println(“Rails session id is “+rails_session_id);

//query rails app if this session id is from a logged in user

boolean valid_user =getRailsResponse(railsCheck,rails_session_id);

if (valid_user) {

// pass the request along the filter chain

chain.doFilter(request, response);

} else {

System.out.println(“valid_user=”+valid_user+“, redirecting to /RedirectServlet”);

ServletContext context =filterConfig.getServletContext();

context.getRequestDispatcher(“/RedirectServlet”).forward(request, response);

}

}

}

public void init(FilterConfig fConfig) throwsServletException {

// TODO Auto-generated method stub

filterConfig = fConfig;

}

}


I couldn’t find how to redirect to an external URL directly from within the servlet filter, so I just forwarded to a second servlet that has the sole job of redirecting to a certain URL (the login page):


package be.vrt.medialab;

import java.io.IOException;

import java.util.ResourceBundle;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


public class RedirectServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

private ResourceBundle resources;

public RedirectServlet() {

super();

resources = ResourceBundle.getBundle(“config”);

}

protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException {

String invalidUrl=resources.getString(“InvalidUrl”);

response.sendRedirect(invalidUrl);

}


protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException {

String invalidUrl=resources.getString(“InvalidUrl”);

response.sendRedirect(invalidUrl);

}

}

import java.io.BufferedReader;

Now the only thing we have to do is place the classes in our web application and change the web.xml as follows:

<?xml version=“1.0” encoding=“UTF-8”?>

<web-appxmlns:xsi=http://www.w3.org/2001/XMLSchema-instance&#8221;xmlns=http://java.sun.com/xml/ns/javaee&#8221;xmlns:web=http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&#8221;xsi:schemaLocation=http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&#8221;id=“WebApp_ID” version=“2.5”>

<display-name>IfipUploader</display-name>

<welcome-file-list>

<welcome-file>TestPage.html</welcome-file>

<welcome-file>FormUpload.html</welcome-file>

<welcome-file>index.jsp</welcome-file>

<welcome-file>default.html</welcome-file>

<welcome-file>default.htm</welcome-file>

<welcome-file>default.jsp</welcome-file>

</welcome-file-list>

<filter>

<filter-name>Rails Authentication</filter-name>

<filter-class>be.vrt.medialab.filters.RailsAuthentication</filter-class>

</filter>

<filter-mapping>

<filter-name>Rails Authentication</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

<servlet>

<servlet-name>RedirectServlet</servlet-name>

<display-name>RedirectServlet</display-name>

<description>redirects to InvalidUrl</description>

<servlet-class>be.vrt.medialab.RedirectServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>RedirectServlet</servlet-name>

<url-pattern>/RedirectServlet</url-pattern>

</servlet-mapping>

<servlet>

<description>Extension of abstract class UploadServlet</description>

<display-name>UploadServletWithQueue</display-name>

<servlet-name>UploadServletWithQueue</servlet-name>

<servlet-class>be.vrt.medialab.upload.UploadServletWithQueue</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>UploadServletWithQueue</servlet-name>

<url-pattern>/UploadServletWithQueue</url-pattern>

</servlet-mapping>

</web-app>

import java.io.IOException;

Below are two logs from the Java web application:

Logged out: (the Rails session id is from a previous session and thus invalid)

Rails session id is BAh7CToQX2NzcmZfdG9rZW4iMVUyeFJWWWVzc1hUZFNPRDR2dkFUb3lONVFaQlJrVmsxR1h0VzVaS3RmUFU9Og9zZXNzaW9uX2lkIiUyOTg2NDc2NzY0N2RlMGU1OWExMTFiOTUwMTk0Zjg2MCIQaW5pdGlhbF91cmkiDS9tYW1taWUvIgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVyOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--41ae001042b16ee26966fc931d11719bc51d7b71
urlString=http://media.ibbt.be/mammie/session/check
rails returned: false
authentication failed!
valid_user=false, redirecting to /RedirectServlet

Logged in:

Rails session id is BAh7CiIJdXNlcm86CVVzZXIHOhZAYXR0cmlidXRlc19jYWNoZXsAOhBAYXR0cmlidXRlc3sdIg5qb2JfdGl0bGUiF1NpdGUgQWRtaW5pc3RyYXRvciIRb2ZmaWNlX3Bob25lMCIPdXBkYXRlZF9hdCIYMjAwOS0xMC0wOCAxMTo1OToxNiIKdGl0bGUiF3NpdGUgYWRtaW5pc3RyYXRvciIYb3JnYW5pc2F0aW9uX3JlZ2lvbjAiDXVzZXJuYW1lIgphZG1pbiIMY291bnRyeSIHQkUiGW9yZ2FuaXNhdGlvbl9hZGRyZXNzMCIHaWQiBjEiHG9yZ2FuaXNhdGlvbl9kZXBhcnRtZW50MCIWb3JnYW5pc2F0aW9uX2NpdHkwIhRhc3Npc3RhbnRfcGhvbmUwIg9maXJzdF9uYW1lIgphZG1pbiITaGFzaGVkX3Bhc3dvcmQiLWI0NzIwODY3MGU2YmU1ODdhNjE1YTcwZDMzZGRkYmVkNmNhMGNiZjAiD29mZmljZV9mYXgwIhFvcmdhbmlzYXRpb24wIg5sYXN0X25hbWUiFnRoZSBhZG1pbmlzdHJhdG9yIhBhZmZpbGlhdGlvbjAiFm9yZ2FuaXNhdGlvbl90eXBlMCIPY3JlYXRlZF9hdCIYMjAwOS0xMC0wOCAxMTo1OToxNiIKZW1haWwiHmthcmVsLmJyYWVja21hbkBnbWFpbC5jb20iEW1vYmlsZV9waG9uZTAiHW9yZ2FuaXNhdGlvbl9wb3N0YWxfY29kZTAiGW9yZ2FuaXNhdGlvbl9jb3VudHJ5MDoPc2Vzc2lvbl9pZCIlMjk4NjQ3Njc2NDdkZTBlNTlhMTExYjk1MDE5NGY4NjA6EF9jc3JmX3Rva2VuIjFVMnhSVlllc3NYVGRTT0Q0dnZBVG95TjVRWkJSa1ZrMUdYdFc1Wkt0ZlBVPSIQaW5pdGlhbF91cmkiDS9tYW1taWUvIgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVyOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--9857ba6780010c041df44eabbfa5f3943ecbe218
urlString=http://media.ibbt.be/mammie/session/check
rails returned: true
authentication successful!

October 20, 2009 at 11:56 am 1 comment

Older Posts Newer Posts


Feeds

Articles to be written…

Twitter – kr3l

Error: Twitter did not respond. Please wait a few minutes and refresh this page.

my del.icio.us

RSS Google Reader Shared Stuff

  • An error has occurred; the feed is probably down. Try again later.

RSS Listening to..

  • An error has occurred; the feed is probably down. Try again later.