четверг, 15 января 2009 г.

Turn on/off LCD on Thermaltake DH101/Imon LCD 0x0038

After installing lirc, /dev/lcd0 must be avialable.

Turn on clock, with ugly font and 4 equal 9 :(
perl -e 'print pack "H*", "8000000000000088"' > /dev/lcd0

Reset LCD
perl -e 'print pack "H*", "4000000000000088"' > /dev/lcd0

Turn off LCD display
perl -e 'print pack "H*", "8800000000000088"' > /dev/lcd0

вторник, 13 января 2009 г.

Fix of high sensitivity of imon remote pad in lirc

This patch created & tested for Thremaltake DH-101, IMON LCD 0x0038.
As i know,  replacement of the original remote is problematic and i do not wish to change the remote. The patch removes events from casual touches to the  pad controller and does its behaviour similar to VOL/CH keys.

Patch edit only lirc/drivers/lirc_imon/lirc_imon.c, created for lirc cvs snapshot 15.01.2009, patched lirc.

How to install? Download patched lirc.


cd lirc
./autogen.sh
./setup.sh
make


Run irw to look as it works.
Now the remote is quite suitable for use :)

I can't create patch, because new cvs compile with errors and 8.4.a doesn't support it. May be later.

About patch :
This patch fix remote pad sensitivity, code from lirc_imon.c
from cvs 2009.02.19 at line 971, make pad unusable
when i press, for example, left, it generate many events left
and events up/down. Pad works as mouse, but code use only separate
events.

Patch algorithm -
create virtual rectangle with size 160px( +- 80px) and put
pointer to center of it. Then event occurs, it use x,y and
to change it position and doesn't ignore any events.
Then pointer reach border - it generate event from lircd.

Second, very importand part - timings
If i press pad - it generate events every 30-40ms, so if
delay between events > 100ms then user remove finger from pad
and pointer move to rectangle's center.

It fix 'jumping' function.

Third part, if i press left and don't remove finger from part:
it generate event left, then 1 sec ignore events,
then generate event and place pointer to rectangle's center.
On third and next events, i place pointer between border and center.
It increase events speed.
Result: Left .. 1 sec .. Left .. 0.2-0.3 sec .. Left .. 0.1 sec .. Left .. 0.1 sec
But if i remove finger from remote, it set hits count to 0 without delay,
so if i press left fast => generate events fast without 1 sec pause, but 1 press = 1 event :)

Patch source code

static inline int tv2int(const struct timeval *a, const struct timeval *b)
{
int usecs = 0;
int sec = 0;
if ( b->tv_usec > a->tv_usec )
{
usecs = 1000000;
sec--;
}

usecs += a->tv_usec - b->tv_usec;

sec += a->tv_sec - b->tv_sec;
sec *= 1000;
usecs /= 1000;
sec += usecs;

if ( sec < 0 )
sec = 1000;

return sec;
}

//in mseconds, 1.0 sec
#define imon_timeout 1000
//rectangle size in pixels
#define imon_size 80

int imon_pad_fix(int a, int b)
{
struct timeval ct;
static struct timeval prev_time = {0, 0};
static struct timeval hit_time = {0, 0};

static int x = 0;
static int y = 0;
static int prev_result = 0;
static int hits = 0;

int result = 0;

int msec;
int msec_hit;

do_gettimeofday(&ct);
msec = tv2int(&ct, &prev_time);
msec_hit = tv2int(&ct, &hit_time);

if ( msec > 100 )
{
x = 0;
y = 0;
hits = 0;
}

x += a;
y += b;

prev_time = ct;

if ( abs(x) > imon_size || abs(y) > imon_size )
{
if ( abs(y) > abs(x) )
result = (y > 0) ? 0x7f : 0x80;
else
result = (x > 0) ? 0x7f00 : 0x8000;

x = 0;
y = 0;

if ( result == prev_result )
{
hits++;

if ( hits > 3 )
{
switch ( result )
{
case 0x7f: y = 17 * imon_size / 30; break;
case 0x80: y -= 17 * imon_size / 30; break;
case 0x7f00: x = 17 * imon_size / 30; break;
case 0x8000: x -= 17 * imon_size / 30; break;
}
}

if ( hits == 2 && msec_hit < imon_timeout )
{
result = 0;
hits = 1;
}
}
else
{
prev_result = result;
hits = 1;
hit_time = ct;
}

}

return result;
}

in function incoming_packet
at line 971
replace
if ((buf[1] == 0) && ((buf[2] != 0) || (buf[3] != 0))) {
int y = (int)(char)buf[2];
int x = (int)(char)buf[3];
if (abs(abs(x) - abs(y)) < 3) {
return;
} else if (abs(y) > abs(x)) {
buf[2] = 0x00;
buf[3] = (y > 0) ? 0x7f : 0x80;
} else {
buf[3] = 0x00;
buf[2] = (x > 0) ? 0x7f : 0x80;
}
}
to
if ((buf[1] == 0) && ((buf[2] != 0) || (buf[3] != 0))) {
int direction = imon_pad_fix((int)(char)buf[2], (int)(char)buf[3]);
if ( !direction )
return;
buf[2] = direction & 0xFF;
buf[3] = ( direction >> 8 ) & 0xFF;
}