# This template is included at the end of _head.html template -->

hackable blog

To content | To menu | To search

Sunday, June 7 2009

embedded webapp on the freerunner

This weekend, i played with nitrogen on my freerunner :

nitromoko-1

nitromoko-2

nitromoko-3

The funny thing is that it is a full web app with the webserver running on the freerunner. Thanks to the nitrogen framework, the code is not bloated as usual and is quite simple.

Example : the clock is refreshed by the server every minutes with these simple statements:

body() -> 
	Body = [	
    	#panel { class="h1-logo", body = [#image { image="/images/hackable1.gif"} ] },
	    #label { id=clock, text="10:14"},
    	#label { id=mylabel, text="" }
    ],
	wf:comet(fun() -> clock_update(clock) end),
	wf:render(Body).
clock_update(Clock)->
    {_Date, {Hour, Min, _Sec}} = erlang:localtime(),
    Value = io_lib:format("~2.10.0B:~2.10.0B", [Hour, Min]),
    wf:update(Clock, lists:flatten(Value)),
	wf:comet_flush(),
	timer:sleep(1000*60),
    clock_update(Clock).

Last but not least, the client runs well on my laptop too :

nitromoko-4

So we have the best of the both worlds (web & desktop) :

  • access to native resources thanks to erlang
  • event driven code with nitrogen (push with comet)
  • customized ui (jQuery)
  • distributed client (example : accessing the contact list without installing crappy software)

The main drawback is performance (for the ui part) and memory consumption (i need to make some tests to figure out exactly).

The source code for the nitrogen/erlang part is available here : http://blondon.fr/blog/public/web_s... I'll post the whole app (html, media and css) asap.

Thursday, May 21 2009

hackable:1 rev4 and the gprs

I'm using the gprs almost every days during my train trips. It works like a charm although it does not use the muxer. Here are the detailed instructions to use the muxer :

  • change MUX=no to MUX=yes in /usr/bin/p and /usr/bin/x
  • change delay from 5 to 10 in /usr/bin/x (lines 65 & 69)
  • in /etc/ppp/peers/gprs :
    • line 36 : comment the /dev/ttySAC0 option
    • line 42 : uncomment the updetach option
    • line 43 : comment the nodetach option

reload the gui stack (/etc/init.d/xserver-hackable1/restart), wait for registration and launch the p script.

Now you can use the gprs and use the phone as the same time (but the gprs connection will hang when calling)

By the way, in order to improve the phone experience, the latest svn version of the openmoko-gsm-applet now handle the gprs automatically :

  • start when the registration is done
  • stop when starting a call
  • stop when receiving a call
  • restart when call is finished

TODO :

Saturday, February 21 2009

Finger scrolling and the freerunner

The openmoko-today app actually implements a kind of finger scrolling, but i find it very weird. I launch applications instead of scrolling every time i try to scroll.
In order to achieve finger scrolling, i have created a scrolled window with an event box above. The scrollbars are hidden and i'm listening to the button-press, button-release and motion-event signals to handle everything.

How to scroll the window

  1. The initial Y position is saved in the button-press callback.
  2. In the motion-event callback, we have the current Y position. A delta is calculated between theses 2 values
  3. This delta is applied to scroll the window (by changing the GtkAdjustment value).

How to detect a mouse click instead of a scrolling action

In order to detect mouse click instead of scrolling :

  • i launch a short timer when the user click on a button.
  • When the timer expires, the button is saved in a variable and is activated.
  • The timer is canceled whenever the motion-event is fired (and the button variable is cleared).
  • When the user raises his finger (button-release signal of the eventbox), if the button is still here, the clicked signal is fired.

Implementation

The source code for the finger scrolling system can be found in libcommongui .

For an example of usage, see wifig

Saturday, February 14 2009

erlang on hackable:1

Erlang works out of the box on hackable:1

Here are the steps to make a little gtk app :
  • install erlang :

apt-get install erlang

Download gtknode at http://code.google.com/p/gtknode/ Then :

./configure --prefix=/usr
make
make install
  • test and enjoy :
%%%-------------------------------------------------------------------
-module(testerl).

-export([start/0]).

-record(widget, {id, name}).

-define(G(C,A),gtknode:cmd(hello,C,A)).

create_button(Winstruct, Label)->
Id = ?G('Gtk_button_new_with_label',[Label]),
?G('Gtk_box_pack_start', [get_vbox(Winstruct), Id, false, false, 5]),
?G('Gtk_widget_show',[Id]),
Widget = #widget{name = "Name", id=Id},
add_widget_to_struct(Widget, Winstruct).


get_vbox(Winstruct)->
[Vbox] = dict:fetch(vbox, Winstruct),
Vbox.


add_widget_to_struct(Widget, Winstruct) when is_record(Widget, widget)->
Widgets = dict:fetch(widgets, Winstruct),
dict:store(widgets, [Widget|Widgets], Winstruct).

add_to_struct([], Dict)->
Dict;
add_to_struct([{Key, Value}|Tail], Dict)->
DictBis = dict:append(Key, Value, Dict),
add_to_struct(Tail, DictBis).

start() ->
gtknode:start(hello),
Win = ?G('Gtk_window_new',['GTK_WINDOW_TOPLEVEL']),
ScrolledWindow = ?G('Gtk_scrolled_window_new', [ 'NULL', 'NULL']),
?G('Gtk_container_add',[Win,ScrolledWindow]),
?G('Gtk_scrolled_window_set_policy', [ScrolledWindow, 'GTK_POLICY_NEVER', 'GTK_POLICY_ALWAYS']),

Viewport = ?G('Gtk_viewport_new', ['NULL', 'NULL']),
?G('Gtk_container_add',[ScrolledWindow, Viewport]),

Vbox = ?G('Gtk_vbox_new', [false, 0]),
io:fwrite("Vbox = ~p~n", [Vbox]),
?G('Gtk_container_add',[Viewport,Vbox]),

But = ?G('Gtk_button_new_with_label',["butté"]),

?G('Gtk_widget_set_name', [But, "button"]),
?G('Gtk_box_pack_start', [Vbox, But, false, false, 5]),

?G('Gtk_widget_show',[Win]),
?G('Gtk_widget_show',[ScrolledWindow]),
?G('Gtk_widget_show',[Viewport]),
?G('Gtk_widget_show',[Vbox]),
?G('Gtk_widget_show',[But]),
?G('GN_signal_connect',[But,clicked]),
?G('GN_signal_connect',[Win,destroy]),

Winstruct = add_to_struct([{window, Win}, {vbox, Vbox}, {widgets, []}], dict:new()),
loop(Winstruct, But).


loop(Winstruct, But) ->
receive
{hello,{signal,{But,clicked}}} ->
io:fwrite("widget : ~p ~p~n",[But, clicked]),
io:fwrite("winstruct = ~p~n", [Winstruct]),
WinstructB = create_button(Winstruct, "toto va a la plage"),
loop(WinstructB, But);
{hello,{signal,{_,destroy}}} ->
gtknode:stop(hello)
end.
erl -sname anode@localhost
(anode@localhost)1> c(testerl).
(anode@localhost)2> testerl:start().