четверг, 5 февраля 2009 г.

Пульт Gotview USB и Linux

Данное руководство относится как пульту с функцией on/off, так и без on/off.
Спасибо shashurup - за помощь

Под windows пульт работает как обычная клавиатура/мышь - проблем нет. Но я его брал для linux там оказались проблемы, как клавиатуру/мышь подключать его не стало, /dev/input/event не появились. Зато появилось два usb устрйства - /dev/usb/hiddev0, /dev/usb/hiddev1 (Проверял на ядрах 2.6.27, 2.6.28 х86 и х64 ).

по lsusb получил:
Bus 004 Device 007: ID 0419:0001 Samsung Info. Systems America, Inc. IrDA Remote Controller


Путем гугления нашел как его заставить работать, нужно использовать lirc с драйвером Samsung
./configure --prefix=/usr --with-driver=samsung


Но у меня есть стойкое подозрение, что это немного не то устройство - и с lirc он работал некорректно - дублировалась половина кнопок, сначала я думал что неправильно заданы настройки в lircd.conf. Анализируя исходные коды, нашел причину дублирования - функция samsung_rec игнорирует состояния кнопок alt,shift..., получается что ctrl + alt + shift + 9 и просто 9 генерируют одинаковый код. Под это дело я написал новую функцию - gotview_rec, статусы alt,ctrl... храню в 1 байте и его добавляю к коду кнопки - теперь все комбинации генерируют разные коды, кнопки не путаются.

Следующая проблема - при нажатии на крестовину генерирует несколько нажатий клавиш, repeat в lircrc почему-то не помог, проскакивает несколько нажатий сразу. delay преследует немного другие цели, по этому сделал еще один патч - после первого нажатия кнопки пропускаются все нажатия кнопки в течении 0.4 сек, потом события обрабатываются без пропуска. Если вам это не нужно - отключить можно, закомментировав 908 строчку hw_hiddev.c
// if ( gotview_check_key(main_code) )


Теперь сама инструкция :)
1. Скачивайте lirc-0.8.4a с сайта www.lirc.org
http://prdownloads.sourceforge.net/lirc/lirc-0.8.4a.tar.bz2
2. Скачивайте пропатченный hw_hiddev.c
3. Распакуйте lirc-0.8.4a и замените в нем daemons/hw_hiddev.c на пропатченный.
4. Конфигурим и компилируем
./configure --with-driver=samsung
make
make install

5. Скачиваем конфиг lircd.conf и ложим его в /etc
6. Втыкаем usb ресивер и смотрим какие девайсы появились в /dev/usb
В моем случае это hiddev0 и hiddev1
7. Запускаем lircd
/usr/sbin/lircd -H samsung -d /dev/usb/hiddev0 --pidfile=/var/run/lirc0.pid --listen=8765
/usr/sbin/lircd -H samsung -d /dev/usb/hiddev1 --pidfile=/var/run/lirc1.pid --output=/dev/lircd --connect=localhost:8765

8. Запускаем irw и жмем на кнопки пульта, если все прошло успешно - должны появится сообщения о нажатых клавишах, если нет - переходите к первому шагу и делайте все более внимательно :)

четверг, 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;
}