Sunday, July 8, 2007

Control Progress

After downloading the MythTV package from MythTV.org's Downloads page and compiling mythlcdserver, I discovered that KnoppMyth used a slightly newer version of the files (and resulting libraries). Wasted a lot of time there, but got the last stable release out of subversion (which, fortunately, was the same version used by KnoppMyth), and I am now able to compile MythTV modules with the correct library. Mostly. I am getting this error with mythtranscode/replex:

/usr/lib/libmythavcodec-0.20.1.so: undefined reference to `XvMCLoadQMatrix'
/usr/lib/libmythavcodec-0.20.1.so: undefined reference to `XvMCSyncSurface'
/usr/lib/libmythavcodec-0.20.1.so: undefined reference to `XvMCFlushSurface'
/usr/lib/libmythavcodec-0.20.1.so: undefined reference to `XvMCBeginSurface'
collect2: ld returned 1 exit status
make: *** [mythreplex] Error 1

But I intend to ignore it for now as it happens after mythlcdserver is compiled. (This is going to bug people searching for an answer to this problem and finding none. Sorry. Hopefully I'll find out more for a later post, because I'd like to solve this as well before I get desirous to compile and install a brand new release of MythTV.)

I made the following changes to mythlcdserver/lcdprocclient.cpp:

ChangedTo
lcd_keystring = gContext->GetSetting("LCDKeyString", "ABCDEF");lcd_keystring = gContext->GetSetting("LCDKeyString", "A B C D E F");
aString = "client_del_key " + expandString(old_keystring);aString = "client_del_key " + old_keystring;
aString = "client_add_key " + expandString(lcd_keystring);aString = "client_add_key " + lcd_keystring;

Judging from the expandString function, apparently lcdproc used to take single-character "keys", all concatenated in one string (i.e. "ABCDEF" representing six keys), whereas now it can use longer names, and the functions take a space-delimited list. My guess is that, in order to make MythTV compatible with old configuration values, they chose to stick to the single-character key designations and assume all configuration strings were such, and the expandString function puts a space between each character (if lcdproc is version 0.5 or higher). Some of the lcdproc drivers even have a provision for mapping their keys to a single-letter designation. The driver for picoLCD does not, though. So, my solution is to make mythlcdserver use key names instead of key letters, by simply removing the call to expandString and treating the LCDKeyString value as a space-delimited string.

So far, I've had a bit of success. When I compiled mythlcdserver with my changes and used a LCDKeyString value of "Plus Minus F1 F2 F3 F4 F5 Up Down Left Right Enter", I was actually able to control MythTV with the keypad. Sort of. The

+
key moved the menu selection up, and the
-
key selected the menu option. None of the other keys did anything (except after pressing all of them quickly to see if anything else would work, it stopped responding altogether; I suspect a bug in the picoLCD driver). When I changed the LCDKeyString value to "Up Down Left Right Enter", Up moved the cursor up and Down selected. So I have at least solved the problem of getting the keypad and the mythlcdserver program speaking the same language.

I have to say there is an annoyance that makes this whole process much more difficult, in that mythlcdserver doesn't work from the command line. Oh, it starts all right. Even connects to MythTV and gets status updates. It just can't connect to LCDd. I keep getting "connection refused" from LCDd, whether I run as mythtv or as root. Can't figure out the problem there.

The reading of the key press appears to be handled by the library libmyth, via lcddevice.cpp. It is under the same assumption that the LCDKeyString value represents a list of non-delimited, single-character keys. In fact, the translation is done by taking the key name reported (actually just the first character thereof), finding the position it matches in LCDKeyString, and using that position as a "magic number" translation to a key press. Using my edited code, the key press for "Up" would cause it to look for a "U", find it at position 0, and translate that as Key_Up. "Down" caused it to find a "D" at position 3, thereby sending Key_Right (which happens to select a menu option).

To "fix" this, I am rewriting the LCD::handleKeyPress function. It is, for the moment, quite simple:

void LCD::handleKeyPress(QString key_pressed) {
    int key = 0;

    if (key_pressed == "Up")
        key = Qt::Key_Up;
    else if (key_pressed == "Down")
        key = Qt::Key_Down;
    else if (key_pressed == "Left")
        key = Qt::Key_Left;
    else if (key_pressed == "Right")
        key = Qt::Key_Right;
    else if (key_pressed == "Enter")
        key = Qt::Key_Space;
    else if (key_pressed == "Plus")
        key = Qt::Key_Home;
    else if (key_pressed == "Minus")
        key = Qt::Key_End;
    else if (key_pressed == "F1")
        key = Qt::Key_F1;
    else if (key_pressed == "F2")
        key = Qt::Key_X;
    else if (key_pressed == "F3")
        key = Qt::Key_I;
    else if (key_pressed == "F4")
        key = Qt::Key_Escape;
    else if (key_pressed == "F5")
        key = Qt::Key_M;

    QApplication::postEvent(gContext->GetMainWindow(),
         new ExternalKeycodeEvent(key));
}

I think there is oodles of room for improvement. Some way to map keys would be ideal. I was kind of hoping I could use the keybindings table, maybe get the LCD module to report a key of, say, "LCD_UP", and have that text in the keybindings table to identify what action LCD_UP performs. Maybe if I have time, I'll work on that. Right now, I'll just keep my fingers crossed for a clean [enough] compile, install the library, and see if I managed to make this thing usable.

And... It's no good. The front end never appeared, and the LCD showed LCDd's default screen (0 clients). The mythfrontend.log file gave me a clue, though:

sh: /usr/local/bin/mythlcdserver: No such file or directory
[...]
Couldn't find theme Titivillus

The big clue is that I have mythlcdserver in /usr/bin/, not /usr/local/bin/. I'm going to hazard a guess that there is a path that gets compiled into the library that is different than the default KnoppMyth layout.

4 comments:

Dan said...

Hello,

Sorry to read about the crash of your box. Mine stopped working due to a fried harddrive so im rebuilding with a knoppmyth r5.5 :)

I found your blog on the LCD-keystrokes-subject very useful and while posting this comment im trying to build a mythtv 0.22rc1 tarball with your modifications to lcdprocclient.cpp :)

However, as this is my first attempt at building this on my own im expecting lots of errors and am wondering if theres any way to build the mythlcdserver as a sort of "standalone" just so that i could run the commandline version from 22rc1 and see if it works with my brand new lcdd/lcdproc 5.3.0 with CFontzPacket-support.

It gets a bit tedious having to deal with build-errors from ie. "mythfreesurround" and other parts that are irrelevant to my debugging of keystrokes.

Thanks for a great blog about MythTV :)

Dan said...

Heh, I kinda figured it out.
configure and then make the whole project (no need for make install afaik when it comes to testing).
When all is build Makefiles will be generated for each "module" and then you can rebuild those separate modules in "program" and "libs" folders in source.
(Sorry to pollute your blog with this).

Another problem has occured though. The protocol version is a mismatch compared to the rest of my mythtv-installation. This is due to me running knoppmythR5.5 based on 0.21 and compiling mythlcdserver from a .22rc1 tarball (silly me!).
I'll try to find the exact version used by knoppmyth and then I'll dive into the .cpp files. I have some basic C-experiences but Im no ace at all.

Perhaps I might keep you updated anyway if I make some progress with the keystrokes ?

Yakko Warner said...

By all means, comment away!

Unfortunately, I haven't spent any time with my own, since it still doesn't power up. Maybe someday...

Dan said...

Thanks :) ...and good news everyone, I got it all working now.

I found a 0.21 release of mythtv which used the same protocol as the KM-version. Worked my way through compiling it (takes quite a few hours on a Via 800MHz!) and then i started hacking the lcdprocclient.cpp. Nothing happened, I copy-pasted lots of VERBOSE-outputs here and there in the code yet still no sound from the keypad. I tried building LCDProc 0.5.3 instead of the 5.2 I was using, no difference.
It seems mythlcdserver from both 0.21 -and- 0.22 works best with LCDProc 0.5.2 and I got it to a state where I could see all the yummy stuff in 0.22 with dedicated screens for controlling the frontend on my LCD, pretty neat! (although all screens said ("don't work yet") but it seems there will be future direct control for volume, music, channel and so on by navigating the screens).

Anyway, another problem was that no matter what I put in LCDd.conf I always got the same keystroke-names in the log/output from LCDd. This was bugging me and so I came up with the idea of checking the CFontzPacket.c file which came with the drivers for LCDProc 5.3 (my LCD is a CrystalFontz 635-USB). I had a feeling the key-names were hardcoded. And there it was:
case CFP_KEY_LEFT:
return "Left";
break;
case CFP_KEY_UP:
return "Up";
break;
case CFP_KEY_DOWN:
return "Down";
break;
case CFP_KEY_RIGHT:
return "Right";
break;
case CFP_KEY_ENTER:
return "Enter";
break;
case CFP_KEY_ESCAPE:
return "Escape";
break;
case CFP_KEY_UL_PRESS:
return "Up";
break;
case CFP_KEY_UR_PRESS:
return "Enter";
break;
case CFP_KEY_LL_PRESS:
return "Down";
break;
case CFP_KEY_LR_PRESS:
return "Escape";
break;

After a few trial-and-errors finding the right key=capital-letter I changed the CFP_KEY_XXXX-lines to read C A B D E F and then crossing my fingers while building the object (remember its a 5.3 build and Im copying the binary CFontzPacket.so file to a 5.2 lcdproc (yes, this is how -not- to do it) ...and voila ! Full 6-Key pad control for MythTV :)

Im really excited about this because i have been longing for it for quite some time I just didnt have the courage to try tinkering with it.

Lots of thanks to Yakko Warner for writing this highly useful yet very niche-ish blog about keypads and LCD's, it inspired me and got me on the right path to a solution :)
Thankyou so much :)

I hope you can somehow do the same trick and perhaps hack the driver for your LCD (if you havent tried it yet). I realise that this should be made in a generic way that would let users remap the key-names but it seems to me that the LCDProc-project unfortunately is going slower and slower every day.
There are some alternatives emerging in the horizon I think. A guy is writing a Java-API for LCD's which made it to sourceforge a while ago and it looks interesting.