From ca6cbb9609c8485b6697afc64256e18beb998de3 Mon Sep 17 00:00:00 2001 From: John Pietrzak Date: Fri, 10 Feb 2012 11:23:15 -0500 Subject: [PATCH] First Extras-Testing Candidate Release Pierogi has reached a sufficient level of stability that I'd like to submit it to Extras-Testing. So, I'm again increasing the version number (to 0.6), and working on any extra cleanup necessary. Also in this update, new MCE keysets and fixes to the Toshiba keysets. --- doc/about.html | 17 +- keysets/bose.cpp | 6 +- keysets/mce.cpp | 165 +++++++++++++++++++ keysets/mce.h | 72 +++++++++ keysets/sony.cpp | 16 +- keysets/toshiba.cpp | 88 +++++----- pierogi.pro | 8 +- pierogi.pro.user | 10 +- pirkeysetmanager.cpp | 10 ++ pirmakenames.cpp | 1 + pirmakenames.h | 1 + protocols/mceprotocol.cpp | 261 ++++++++++++++++++++++++++++++ protocols/mceprotocol.h | 47 ++++++ qtc_packaging/debian_fremantle/changelog | 14 ++ qtc_packaging/debian_fremantle/control | 4 +- 15 files changed, 659 insertions(+), 61 deletions(-) create mode 100644 keysets/mce.cpp create mode 100644 keysets/mce.h create mode 100644 protocols/mceprotocol.cpp create mode 100644 protocols/mceprotocol.h diff --git a/doc/about.html b/doc/about.html index f0a62be..6843f34 100644 --- a/doc/about.html +++ b/doc/about.html @@ -9,18 +9,17 @@ Pierogi UIRC

A Universal Infrared Remote Control

-Version 0.5 -- "Half-Way Usable" +Version 0.6

-Note: while this app is in a fairly usable state, the keysets are still -incomplete and mostly untested. Many brands of device are not yet supported, -and those which have keysets may only work in a limited manner. Please do -post on the -Pierogi Forum Board -if you find bugs to fix, have suggestions on future enhancements, or have -particular devices or brands you would like to see added to the list of -keysets. Thank you! +A tasty little app for controlling all your infrared devices. As of this +version, the keysets are still limited and mostly untested. If you find +problems or if you'd like to see keysets for more devices added, please send +me a note at jpietrzak8@gmail.com +or leave a post on the + +Pierogi message board. Thank you!

diff --git a/keysets/bose.cpp b/keysets/bose.cpp index dc07781..6ce7e1e 100644 --- a/keysets/bose.cpp +++ b/keysets/bose.cpp @@ -58,12 +58,13 @@ BoseRadio2::BoseRadio2( addKey("on/off", Power_Key, 0x00, 8); addKey("4", Four_Key, 0x08, 8); - addKey("am", Unmapped_Key, 0x10, 8); + addKey("am", Red_Key, 0x10, 8); // sort of a hack to get AM in addKey("6", Six_Key, 0x20, 8); addKey("trackprev", Previous_Key, 0x30, 8); + addKey("trackprev", ChannelDown_Key, 0x30, 8); addKey("volup", VolumeUp_Key, 0x40,8); addKey("cdstop", Stop_Key, 0x50, 8); - addKey("fm", Unmapped_Key, 0x60, 8); + addKey("fm", Green_Key, 0x60, 8); // also hack addKey("2", Two_Key, 0x70, 8); addKey("mute", Mute_Key, 0x80, 8); addKey("5", Five_Key, 0x88, 8); @@ -73,6 +74,7 @@ BoseRadio2::BoseRadio2( addKey("1", One_Key, 0xB0, 8); addKey("voldown", VolumeDown_Key, 0xC0, 8); addKey("tracknext", Next_Key, 0xD0, 8); + addKey("tracknext", ChannelUp_Key, 0xD0, 8); addKey("aux", AuxInput_Key, 0xE0, 8); addKey("3", Three_Key, 0xF0, 8); } diff --git a/keysets/mce.cpp b/keysets/mce.cpp new file mode 100644 index 0000000..8309a66 --- /dev/null +++ b/keysets/mce.cpp @@ -0,0 +1,165 @@ +#include "mce.h" +#include "protocols/mceprotocol.h" + +MCERemote1::MCERemote1( + QObject *guiObject, + unsigned int index) + : PIRKeysetMetaData( + "MCE Remote mode 1", + Microsoft_Make, + index) +{ + threadableProtocol = new MCEProtocol(guiObject, index, 0x800F); + + setPreData(0x04, 7); + + addKey("Zero", Zero_Key, 0x00, 8); + addKey("One", One_Key, 0x01, 8); + addKey("Two", Two_Key, 0x02, 8); + addKey("Three", Three_Key, 0x03, 8); + addKey("Four", Four_Key, 0x04, 8); + addKey("Five", Five_Key, 0x05, 8); + addKey("Six", Six_Key, 0x06, 8); + addKey("Seven", Seven_Key, 0x07, 8); + addKey("Eight", Eight_Key, 0x08, 8); + addKey("Nine", Nine_Key, 0x09, 8); + addKey("Clear", Clear_Key, 0x0A, 8); + addKey("Enter", Enter_Key, 0x0B, 8); + + addKey("Power", Power_Key, 0x0C, 8); + addKey("Home", Menu_Key, 0x0D, 8); + addKey("Mute", Mute_Key, 0x0E, 8); + addKey("MoreInfo", Info_Key, 0x0F, 8); + addKey("VolUp", VolumeUp_Key, 0x10, 8); + addKey("VolDown", VolumeDown_Key, 0x11, 8); + addKey("ChanUp", ChannelUp_Key, 0x12, 8); + addKey("ChanDown", ChannelDown_Key, 0x13, 8); + + addKey("Forward", FastForward_Key, 0x14, 8); + addKey("Rewind", Rewind_Key, 0x15, 8); + addKey("Play", Play_Key, 0x16, 8); + addKey("Record", Record_Key, 0x17, 8); + addKey("Pause", Pause_Key, 0x18, 8); + addKey("Stop", Stop_Key, 0x19, 8); + addKey("Skip", Advance_Key, 0x1A, 8); + addKey("Replay", Replay_Key, 0x1B, 8); + + addKey("Hash", Unmapped_Key, 0x1C, 8); // "Caps Lock" + addKey("Star", Unmapped_Key, 0x1D, 8); // "Mouse" + + addKey("Up", Up_Key, 0x1E, 8); + addKey("Down", Down_Key, 0x1F, 8); + addKey("Left", Left_Key, 0x20, 8); + addKey("Right", Right_Key, 0x21, 8); + addKey("OK", Select_Key, 0x22, 8); + addKey("Back", Exit_Key, 0x23, 8); + addKey("DVD", DiscMenu_Key, 0x24, 8); + addKey("LiveTV", LiveTV_Key, 0x25, 8); + addKey("Guide", Guide_Key, 0x26, 8); + + addKey("Aspect", AspectRatio_Key, 0x27, 8); + + addKey("Visualization", Unmapped_Key, 0x32, 8); + addKey("SlideShow", Unmapped_Key, 0x33, 8); + addKey("Eject", Eject_Key, 0x34, 8); + + addKey("TV", Unmapped_Key, 0x46, 8); // "My TV" + addKey("Music", Unmapped_Key, 0x47, 8); // "My Music" + addKey("RecTV", Unmapped_Key, 0x48, 8); // "Recorded TV" + addKey("Pictures", Unmapped_Key, 0x49, 8); // "My Pictures" + addKey("Videos", Unmapped_Key, 0x4A, 8); // "My Videos" + addKey("DVD angle", Angle_Key, 0x4B, 8); + addKey("DVD audio", Audio_Key, 0x4C, 8); + addKey("DVD subtitle", Captions_Key, 0x4D, 8); + + addKey("Print", Unmapped_Key, 0x4E, 8); + addKey("Radio", TunerInput_Key, 0x50, 8); + + addKey("Teletext", Teletext_Key, 0x5A, 8); + addKey("Red", Red_Key, 0x5B, 8); + addKey("Green", Green_Key, 0x5C, 8); + addKey("Yellow", Yellow_Key, 0x5D, 8); + addKey("Blue", Blue_Key, 0x5E, 8); + +// addKey("PlayPause", Play_Key, 0x6E, 8); +// addKey("PlayPause", Pause_Key, 0x6E, 8); + + addKey("Media", Unmapped_Key, 0x80, 8); // "Write" +} + + +MCERemote1a::MCERemote1a( + QObject *guiObject, + unsigned int index) + : MCERemote1(guiObject, index) +{ + setKeysetName("MCE Remote mode 2"); + + setPreData(0x14, 7); +} + + +MCERemote1b::MCERemote1b( + QObject *guiObject, + unsigned int index) + : MCERemote1(guiObject, index) +{ + setKeysetName("MCE Remote mode 3"); + + setPreData(0x24, 7); +} + + +MCERemote1c::MCERemote1c( + QObject *guiObject, + unsigned int index) + : MCERemote1(guiObject, index) +{ + setKeysetName("MCE Remote mode 4"); + + setPreData(0x34, 7); +} + + +MCERemote1d::MCERemote1d( + QObject *guiObject, + unsigned int index) + : MCERemote1(guiObject, index) +{ + setKeysetName("MCE Remote mode 5"); + + setPreData(0x44, 7); +} + + +MCERemote1e::MCERemote1e( + QObject *guiObject, + unsigned int index) + : MCERemote1(guiObject, index) +{ + setKeysetName("MCE Remote mode 6"); + + setPreData(0x54, 7); +} + + +MCERemote1f::MCERemote1f( + QObject *guiObject, + unsigned int index) + : MCERemote1(guiObject, index) +{ + setKeysetName("MCE Remote mode 7"); + + setPreData(0x64, 7); +} + + +MCERemote1g::MCERemote1g( + QObject *guiObject, + unsigned int index) + : MCERemote1(guiObject, index) +{ + setKeysetName("MCE Remote mode 8"); + + setPreData(0x74, 7); +} diff --git a/keysets/mce.h b/keysets/mce.h new file mode 100644 index 0000000..406ecca --- /dev/null +++ b/keysets/mce.h @@ -0,0 +1,72 @@ +#ifndef MCE_H +#define MCE_H + +#include "pirkeysetmetadata.h" + +class QObject; + +class MCERemote1: public PIRKeysetMetaData +{ +public: + MCERemote1( + QObject *guiObject, + unsigned int index); +}; + +class MCERemote1a: public MCERemote1 +{ +public: + MCERemote1a( + QObject *guiObject, + unsigned int index); +}; + +class MCERemote1b: public MCERemote1 +{ +public: + MCERemote1b( + QObject *guiObject, + unsigned int index); +}; + +class MCERemote1c: public MCERemote1 +{ +public: + MCERemote1c( + QObject *guiObject, + unsigned int index); +}; + +class MCERemote1d: public MCERemote1 +{ +public: + MCERemote1d( + QObject *guiObject, + unsigned int index); +}; + +class MCERemote1e: public MCERemote1 +{ +public: + MCERemote1e( + QObject *guiObject, + unsigned int index); +}; + +class MCERemote1f: public MCERemote1 +{ +public: + MCERemote1f( + QObject *guiObject, + unsigned int index); +}; + +class MCERemote1g: public MCERemote1 +{ +public: + MCERemote1g( + QObject *guiObject, + unsigned int index); +}; + +#endif // MCE_H diff --git a/keysets/sony.cpp b/keysets/sony.cpp index 996dcde..ba1abfd 100644 --- a/keysets/sony.cpp +++ b/keysets/sony.cpp @@ -467,6 +467,10 @@ SonyDVD1::SonyDVD1( addSIRC20Key("top_menu", DiscTitle_Key, 0x49, 0x1A, 0x1A); // "Title" addSIRC20Key("dvd_menu", DiscMenu_Key, 0x49, 0x1A, 0x1B); addSIRC20Key("program", Program_Key, 0x49, 0x1A, 0x1F); + addSIRC20Key("step/search -", StepBack_Key, 0x49, 0x1A, 0x20); + addSIRC20Key("step/search +", StepForward_Key, 0x49, 0x1A, 0x21); + addSIRC20Key("scan/slow -", SlowMinus_Key, 0x49, 0x1A, 0x22); + addSIRC20Key("scan/slow +", SlowPlus_Key, 0x49, 0x1A, 0x23); addSIRC20Key("INDEX-", Unmapped_Key, 0x49, 0x1A, 0x26); addSIRC20Key("INDEX+", Unmapped_Key, 0x49, 0x1A, 0x27); addSIRC20Key("TIME", Unmapped_Key, 0x49, 0x1A, 0x28); @@ -486,8 +490,8 @@ SonyDVD1::SonyDVD1( addSIRC20Key("X2_FORWARD", Unmapped_Key, 0x49, 0x1A, 0x37); addSIRC20Key("stop", Stop_Key, 0x49, 0x1A, 0x38); addSIRC20Key("pause", Pause_Key, 0x49, 0x1A, 0x39); - addSIRC20Key("STEP_BACK", StepBack_Key, 0x49, 0x1A, 0x3A); // "Jog Rev" - addSIRC20Key("STEP_FORWARD", StepForward_Key, 0x49, 0x1A, 0x3B); // "Jog Fwd" + addSIRC20Key("STEP_BACK", Unmapped_Key, 0x49, 0x1A, 0x3A); // "Jog Rev" + addSIRC20Key("STEP_FORWARD", Unmapped_Key, 0x49, 0x1A, 0x3B); // "Jog Fwd" addSIRC20Key("RecStop", RecordStop_Key, 0x49, 0x1A, 0x3D); addSIRC20Key("RecPause", RecordPause_Key, 0x49, 0x1A, 0x3E); @@ -518,11 +522,17 @@ SonyDVD1::SonyDVD1( addSIRC20Key("Guide", Guide_Key, 0x62, 0x1A, 0x16); addSIRC20Key("Options", Unmapped_Key, 0x62, 0x1A, 0x17); // "Tools" addSIRC20Key("Dot", Unmapped_Key, 0x62, 0x1A, 0x1D); + addSIRC20Key("file", Unmapped_Key, 0x62, 0x1A, 0x20); + addSIRC20Key("sort", Unmapped_Key, 0x62, 0x1A, 0x21); + addSIRC20Key("edit", Unmapped_Key, 0x62, 0x1A, 0x22); addSIRC20Key("ALBUM-MINUS", Unmapped_Key, 0x62, 0x1A, 0x29); addSIRC20Key("ALBUM-PLUS", Unmapped_Key, 0x62, 0x1A, 0x2A); addSIRC20Key("F1", Unmapped_Key, 0x62, 0x1A, 0x2E); // "HDD" addSIRC20Key("F2", Unmapped_Key, 0x62, 0x1A, 0x2F); // "DVD" - addSIRC20Key("DiscSkip", NextDisc_Key, 0x62, 0x1A, 0x3E); + addSIRC20Key("picture memory", Unmapped_Key, 0x62, 0x1A, 0x3C); + addSIRC20Key("disc skip -", PrevDisc_Key, 0x62, 0x1A, 0x3D); + addSIRC20Key("DiscSkip", NextDisc_Key, 0x62, 0x1A, 0x3E); // "disc skip +" + addSIRC20Key("folder", Unmapped_Key, 0x62, 0x1A, 0x40); addSIRC20Key("Favorites", Favorites_Key, 0x62, 0x1A, 0x5E); addSIRC20Key("Purple", Blue_Key, 0x62, 0x1A, 0x66); addSIRC20Key("Red", Red_Key, 0x62, 0x1A, 0x67); diff --git a/keysets/toshiba.cpp b/keysets/toshiba.cpp index c828c2f..8cac3e6 100644 --- a/keysets/toshiba.cpp +++ b/keysets/toshiba.cpp @@ -29,17 +29,15 @@ ToshibaTV1::ToshibaTV1( addKey("100", PlusOneHundred_Key, 0x0A, 8); addKey("-/--", DoubleDigit_Key, 0x0B, 8); addKey("reset", Reset_Key, 0x0C, 8); - addKey("textzoom", TeletextSize_Key, 0x0D, 8); // "Enlarge" addKey("tv/video", Unmapped_Key, 0x0F, 8); // "input" addKey("MUTE", Mute_Key, 0x10, 8); - addKey("BLANK", PictureMode_Key, 0x11, 8); // "Contrast", "picture_preset" + addKey("picturepref", PictureMode_Key, 0x11, 8); // "Contrast", "PP" addKey("POWER", Power_Key, 0x12, 8); - addKey("mts", FMMode_Key, 0x13, 8); // "audio_stereo_2channel" + addKey("mts", Audio_Key, 0x13, 8); // "audio_stereo_2channel" addKey("SCART", Input_Key, 0x14, 8); // "AV", "inputs", "source" - addKey("sleep", Sleep_Key, 0x15, 8); // Clock + addKey("sleep", Sleep_Key, 0x15, 8); addKey("CALL", Call_Key, 0x16, 8); addKey("ent", Enter_Key, 0x17, 8); // "ch_rtn" - addKey("TXT/MIX", Teletext_Key, 0x17, 8); addKey("fav+", Unmapped_Key, 0x19, 8); addKey("V+", VolumeUp_Key, 0x1A, 8); addKey("V+", Right_Key, 0x1A, 8); @@ -53,8 +51,6 @@ ToshibaTV1::ToshibaTV1( addKey("P-", Down_Key, 0x1F, 8); addKey("OK", Select_Key, 0x21, 8); addKey("POP_DIR", Unmapped_Key, 0x26, 8); - addKey("textindex", TeletextIndex_Key, 0x2B, 8); - addKey("textpages", Unmapped_Key, 0x2C, 8); addKey("a/d", Unmapped_Key, 0x44, 8); addKey("RED", Red_Key, 0x48, 8); addKey("GREEN", Green_Key, 0x49, 8); @@ -66,18 +62,15 @@ ToshibaTV1::ToshibaTV1( addKey("locate", PIPMove_Key, 0x4E, 8); addKey("source", PIPSource_Key, 0x4F, 8); addKey("pip", PIP_Key, 0x51, 8); - addKey("Double_Arrow", Unmapped_Key, 0x52, 8); // "swap", but not pip!; "back" addKey("swap", PIPSwap_Key, 0x53, 8); // Reduce - addKey("texthold", TeletextHold_Key, 0x53, 8); addKey("PIC_SIZE", AspectRatio_Key, 0x54, 8); // "16:9" - addKey("textanswer", TeletextReveal_Key, 0x54, 8); // "?" addKey("Tone", Unmapped_Key, 0x55, 8); addKey("cap/text", Captions_Key, 0x57, 8); // Image addKey("exit", Exit_Key, 0x58, 8); addKey("SIZE", AspectRatio_Key, 0x59, 8); // "WIDE" addKey("DOULBY", NoiseReduction_Key, 0x5A, 8); - addKey("1/2", Audio_Key, 0x63, 8); // "cap1/cap2" addKey("MENU", Menu_Key, 0x5B, 8); + addKey("1/2", Unmapped_Key, 0x63, 8); // "cap1/cap2" addKey("CLOCK", Timer_Key, 0x71, 8); // "TIMER" addKey("TV", Unmapped_Key, 0x72, 8); addKey("SEARCH", Unmapped_Key, 0x8F, 8); @@ -120,37 +113,39 @@ ToshibaTV1b::ToshibaTV1b( ToshibaTV1c::ToshibaTV1c( QObject *guiObject, unsigned int index) - : ToshibaTV1(guiObject, index) + : ToshibaTV1f(guiObject, index) { setKeysetName("TV Keyset 1c"); - addKey("exit", Exit_Key, 0xC23D, 16); - addKey("pipswap", PIPSwap_Key, 0x1AE5, 16); - addKey("osdinfo", Info_Key, 0x6897, 16); + addKey("textzoom", TeletextSize_Key, 0x0D, 8); // "Enlarge" + addKey("texttime", TeletextTime_Key, 0x15, 8); + addKey("TXT/MIX", Teletext_Key, 0x17, 8); // "teletext" + addKey("textindex", TeletextIndex_Key, 0x2B, 8); + addKey("textpages", Unmapped_Key, 0x2C, 8); + addKey("texthold", TeletextHold_Key, 0x53, 8); + addKey("textanswer", TeletextReveal_Key, 0x54, 8); + addKey("pipswap", PIPSwap_Key, 0x58, 8); } ToshibaTV1d::ToshibaTV1d( QObject *guiObject, unsigned int index) - : ToshibaTV1(guiObject, index) + : ToshibaTV1f(guiObject, index) { setKeysetName("TV Keyset 1d"); - addKey("Left", Left_Key, 0x42BD, 16); - addKey("Right", Right_Key, 0x02FD, 16); - addKey("Down", Down_Key, 0xB847, 16); - addKey("Up", Up_Key, 0x9867, 16); - addKey("Back", Exit_Key, 0xC23D, 16); - addKey("guide", Guide_Key, 0xA25D, 16); - addKey("tv/fav/radio", Favorites_Key, 0xE21D, 16); // might be wrong - addKey("info", Info_Key, 0x6897, 16); // might be wrong - addKey("subtitle", Captions_Key, 0x30CF, 16); - addKey("stillpicture", Pause_Key, 0x44BB, 16); - addKey("24-", Unmapped_Key, 0x2AD5, 16); - addKey("page-", PageUp_Key, 0xCA35, 16); - addKey("page+", PageDown_Key, 0xB04F, 16); - addKey("24+", Unmapped_Key, 0xA857, 16); + addKey("subtitle", Captions_Key, 0x0C, 8); + addKey("page+", PageDown_Key, 0x0D,8); + addKey("24+", Unmapped_Key, 0x15, 8); + addKey("Up", Up_Key, 0x19, 8); + addKey("Down", Down_Key, 0x1D, 8); + addKey("Right", Right_Key, 0x40, 8); + addKey("Left", Left_Key, 0x42, 8); + addKey("guide", Guide_Key, 0x45, 8); + addKey("tv/fav/radio", Favorites_Key, 0x47, 8); // might be wrong + addKey("page-", PageUp_Key, 0x53, 8); + addKey("24-", Unmapped_Key, 0x54, 8); } @@ -161,12 +156,12 @@ ToshibaTV1e::ToshibaTV1e( { setKeysetName("TV Keyset 1e"); - addKey("STOP", Stop_Key, 0xF20D, 16); - addKey("PLAY", Play_Key, 0x8A75, 16); - addKey("SKIPPREV", Previous_Key, 0x8877, 16); - addKey("SKIPNEXT", Next_Key, 0xCA35, 16); - addKey("frev", Rewind_Key, 0xD22D, 16); - addKey("FFWD", FastForward_Key, 0x52AD, 16); + addKey("SKIPPREV", Previous_Key, 0x11, 8); + addKey("FFWD", FastForward_Key, 0x2A, 8); + addKey("STOP", Stop_Key, 0x40, 8); + addKey("frev", Rewind_Key, 0x4B, 8); + addKey("PLAY", Play_Key, 0x51, 8); + addKey("SKIPNEXT", Next_Key, 0x53, 8); } @@ -179,10 +174,10 @@ ToshibaTV1f::ToshibaTV1f( addControlledDevice(Toshiba_Make, "Regza AV50*", TV_Device); - addKey("back", PrevChannel_Key, 0x4AB5, 16); - addKey("exit", Exit_Key, 0xC23D, 16); - addKey("info", Info_Key, 0x6897, 16); - addKey("stillpicture", Pause_Key, 0x44BB, 16); + addKey("info", Info_Key, 0x16, 8); + addKey("stillpicture", Pause_Key, 0x22, 8); + addKey("exit", Exit_Key, 0x43, 8); + addKey("back", PrevChannel_Key, 0x52, 8); // "Double_Arrow", "swap" } @@ -200,6 +195,19 @@ ToshibaTV1g::ToshibaTV1g( } +ToshibaTV1h::ToshibaTV1h( + QObject *guiObject, + unsigned int index) + : ToshibaTV1b(guiObject, index) +{ + setKeysetName("TV Keyset 1h"); + + addKey("last (prev ch)", PrevChannel_Key, 0x17, 8); + addKey("program guide", Guide_Key, 0x1C, 8); + addKey("pip on/off", PIP_Key, 0x54, 8); +} + + ToshibaVCR1::ToshibaVCR1( QObject *guiObject, unsigned int index) diff --git a/pierogi.pro b/pierogi.pro index 6d624c6..92b1b24 100644 --- a/pierogi.pro +++ b/pierogi.pro @@ -83,7 +83,9 @@ SOURCES += main.cpp mainwindow.cpp \ protocols/aiwaprotocol.cpp \ protocols/kaseikyoprotocol.cpp \ keysets/bose.cpp \ - protocols/boseprotocol.cpp + protocols/boseprotocol.cpp \ + keysets/mce.cpp \ + protocols/mceprotocol.cpp HEADERS += mainwindow.h \ pirkeynames.h \ pirmakenames.h \ @@ -143,7 +145,9 @@ HEADERS += mainwindow.h \ protocols/aiwaprotocol.h \ protocols/kaseikyoprotocol.h \ protocols/boseprotocol.h \ - keysets/bose.h + keysets/bose.h \ + keysets/mce.h \ + protocols/mceprotocol.h FORMS += mainwindow.ui \ pirdocumentationform.ui \ piraboutform.ui \ diff --git a/pierogi.pro.user b/pierogi.pro.user index c6ba144..f703f80 100644 --- a/pierogi.pro.user +++ b/pierogi.pro.user @@ -1,6 +1,6 @@ - + ProjectExplorer.Project.ActiveTarget @@ -79,7 +79,7 @@ dpkg-buildpackage -sa -S -uc -us /Users/john/QtSDK/Maemo/4.6.2/bin/mad false - /Users/john/Develop/n900/pierogi-0.5.2 + /Users/john/Develop/n900/pierogi-0.6.0 Custom Process Step ProjectExplorer.ProcessStep @@ -190,6 +190,7 @@ /Users/john/Develop/n900/pierogi-build-maemo-Qt_for_Fremantle_PR1_3_Devices__Qt_SDK__Release/pierogi_0_1_1_armel.deb /Users/john/Develop/n900/pierogi-build-maemo-Qt_for_Fremantle_PR1_3_Devices__Qt_SDK__Release/pierogi_0_0_1_armel.deb /Users/john/Develop/n900/pierogi-build-maemo-Qt_for_Fremantle_PR1_3_Devices__Qt_SDK__Release/pierogi_0_1_0_armel.deb + /Users/john/Develop/n900/pierogi-build-maemo-Qt_for_Fremantle_PR1_3_Devices__Qt_SDK__Release/pierogi_0_5_3_armel.deb /Users/john/Develop/n900/pierogi-build-maemo-Qt_for_Fremantle_PR1_3_Devices__Qt_SDK__Release/pierogi_0_1_7_armel.deb /Users/john/Develop/n900/pierogi-build-maemo-Qt_for_Fremantle_PR1_3_Devices__Qt_SDK__Release/pierogi_0_5_2_armel.deb /Users/john/Develop/n900/pierogi-build-maemo-Qt_for_Fremantle_PR1_3_Devices__Qt_SDK__Release/pierogi_0_0_1_armel.deb @@ -207,6 +208,7 @@ 192.168.0.15 192.168.0.15 192.168.0.15 + 192.168.0.15 localhost 192.168.0.15 192.168.0.15 @@ -225,6 +227,7 @@ + 2012-02-03T10:04:34 @@ -235,8 +238,9 @@ 2012-01-17T00:15:23 2012-01-14T13:11:32 2012-01-17T00:03:13 + 2012-02-09T18:12:21 2012-01-30T20:23:06 - 2012-02-08T11:55:19 + 2012-02-08T20:29:28 2012-01-01T15:35:35 2012-01-25T13:42:55 2012-02-06T17:22:16 diff --git a/pirkeysetmanager.cpp b/pirkeysetmanager.cpp index a57a398..c2bce33 100644 --- a/pirkeysetmanager.cpp +++ b/pirkeysetmanager.cpp @@ -17,6 +17,7 @@ #include "keysets/jvc.h" #include "keysets/lg.h" #include "keysets/magnavox.h" +#include "keysets/mce.h" #include "keysets/mitsubishi.h" #include "keysets/nokia.h" #include "keysets/panasonic.h" @@ -170,6 +171,15 @@ PIRKeysetManager::PIRKeysetManager( populateKeyset(new MagnavoxConverterBox1(guiObject, counter++)); populateKeyset(new MagnavoxTV1(guiObject, counter++)); + populateKeyset(new MCERemote1(guiObject, counter++)); + populateKeyset(new MCERemote1a(guiObject, counter++)); + populateKeyset(new MCERemote1b(guiObject, counter++)); + populateKeyset(new MCERemote1c(guiObject, counter++)); + populateKeyset(new MCERemote1d(guiObject, counter++)); + populateKeyset(new MCERemote1e(guiObject, counter++)); + populateKeyset(new MCERemote1f(guiObject, counter++)); + populateKeyset(new MCERemote1g(guiObject, counter++)); + populateKeyset(new MitsubishiTV1(guiObject, counter++)); populateKeyset(new MitsubishiTV1a(guiObject, counter++)); populateKeyset(new MitsubishiVCR1(guiObject, counter++)); diff --git a/pirmakenames.cpp b/pirmakenames.cpp index cacbecb..e272745 100644 --- a/pirmakenames.cpp +++ b/pirmakenames.cpp @@ -18,6 +18,7 @@ PIRMakeMgr::PIRMakeMgr() makes[JVC_Make] = "JVC"; makes[LG_Make] = "LG"; makes[Magnavox_Make] = "Magnavox"; + makes[Microsoft_Make] = "Microsoft"; makes[Mitsubishi_Make] = "Mitsubishi"; makes[Nokia_Make] = "Nokia"; makes[Panasonic_Make] = "Panasonic"; diff --git a/pirmakenames.h b/pirmakenames.h index cde6630..ff50d30 100644 --- a/pirmakenames.h +++ b/pirmakenames.h @@ -19,6 +19,7 @@ enum PIRMakeName{ JVC_Make, LG_Make, Magnavox_Make, + Microsoft_Make, Mitsubishi_Make, Nokia_Make, Panasonic_Make, diff --git a/protocols/mceprotocol.cpp b/protocols/mceprotocol.cpp new file mode 100644 index 0000000..9096c7e --- /dev/null +++ b/protocols/mceprotocol.cpp @@ -0,0 +1,261 @@ +#include "mceprotocol.h" + +#include "pirrx51hardware.h" + +#include "pirexception.h" + +#include +extern bool commandInFlight; +extern QMutex commandIFMutex; + +// These defines might need to be turned into variables, for odd devices. +#define HEADER_PULSE 2666 +#define HEADER_SPACE 888 +#define TRAILER_BIPHASE 888 + +// Ok, what I've got on MCE protocol is this: +// It is based on RC6 mode 6A, with a few odd tweaks. +// The biphase unit of time is 444 usec. +// The RC6 header block starts with the normal 2666 usec pulse, 888 usec space. +// The next bit is fixed as a "1", as usual. +// The next three bits are 110, marking this as a mode 6 protocol. +// The trailer bit has an 888 usec biphase, is set to 0, and is _not_ toggled! +// The next 16 bits I'm not sure about. Hopefully they will be a fixed value +// for any given device... +// Then, the next bit is the new toggle bit. +// Following this, there are seven "device address" bits, and then eight +// "command" bits. +// A space of (at least) 2666 usec must follow any command. +// The carrier frequency is 36 kHZ, duty cycle between 25 and 50 %. + +MCEProtocol::MCEProtocol( + QObject *guiObject, + unsigned int index, + unsigned int oemData) + : PIRProtocol(guiObject, index, 2666, false), + biphaseUnit(444), + buffer(0), + keypressCount(0) +{ + setCarrierFrequency(36000); + appendToBitSeq(oemBits, oemData, 16); +} + + +void MCEProtocol::startSendingCommand( + unsigned int threadableID, + PIRKeyName command) +{ + try + { + // Is this command meant for us? + if (threadableID != id) return; + + clearRepeatFlag(); + + KeycodeCollection::const_iterator i = keycodes.find(command); + + // Sanity check: + if (i == keycodes.end()) + { + std::string s = "Tried to send a non-existent command.\n"; + throw PIRException(s); + } + + PIRRX51Hardware rx51device(carrierFrequency, dutyCycle); + + int repeatCount = 0; + int duration = 0; + while (repeatCount < MAX_REPEAT_COUNT) + { + bufferContainsSpace = false; + bufferContainsPulse = false; + // First, construct the "Header" segment of the pulse train. + // + // The header involves: + // a) a "lead" of 2666 us pulse, 888 us space; + // b) a "start bit", value 1 (so 444 us pulse, 444 us space) + // c) three control bits, set to "110" (i.e., mode "6") + // d) the double-sized "trailer" bit, set to 0. + + rx51device.addSingle(HEADER_PULSE); // lead pulse + duration += HEADER_PULSE; + rx51device.addSingle(HEADER_SPACE); // lead space + duration += HEADER_SPACE; + rx51device.addSingle(biphaseUnit); // start bit pulse + duration += biphaseUnit; + rx51device.addSingle(biphaseUnit); // start bit space + duration += biphaseUnit; + rx51device.addSingle(biphaseUnit); // bit 1 pulse; + duration += biphaseUnit; + rx51device.addSingle(biphaseUnit); // bit 1 space; + duration += biphaseUnit; + rx51device.addSingle(biphaseUnit); // bit 2 pulse; + duration += biphaseUnit; + rx51device.addSingle(2 * biphaseUnit); // bit 2 space + bit 3 space; + duration += 2 * biphaseUnit; + rx51device.addSingle(biphaseUnit); // bit 3 pulse; + duration += biphaseUnit; + rx51device.addSingle(2 * biphaseUnit); // trailer space + duration += 2 * biphaseUnit; + buffer = 2 * biphaseUnit; // trailer pulse goes into the buffer + bufferContainsPulse = true; + + // Now, we can start the normal buffering process: + + // push the "OEM" data: + duration += pushBits(oemBits, rx51device); + + // The next bit is the MCE toggle bit: + if (keypressCount % 2) + { + pushOne(rx51device); + } + else + { + pushZero(rx51device); + } + + // push the device address data: + duration += pushBits(preData, rx51device); + + // push the command data: + duration += pushBits((*i).second.firstCode, rx51device); + + // Flush out the buffer, if necessary: + if (buffer) + { + rx51device.addSingle(buffer); + duration += buffer; + buffer = 0; + } + + // Actually send out the command: + rx51device.sendCommandToDevice(); + + // Sleep for an amount of time. (RC6 demands an addtional 6 unit space + // at the end of any command...) + sleepUntilRepeat(duration + 6 * biphaseUnit); + + // Have we been told to stop yet? + if (checkRepeatFlag()) + { + // Yes, we can now quit repeating: + ++keypressCount; + QMutexLocker ciflocker(&commandIFMutex); + commandInFlight = false; + return; + } + } + } + catch (PIRException e) + { + emit commandFailed(e.getError().c_str()); + } + + ++keypressCount; + QMutexLocker cifLocker(&commandIFMutex); + commandInFlight = false; +} + + +int MCEProtocol::pushBits( + const CommandSequence &bits, + PIRRX51Hardware &rx51device) +{ + int duration = 0; + + CommandSequence::const_iterator i = bits.begin(); + + while (i != bits.end()) + { + if (*i) + { + duration += pushOne(rx51device); + } + else + { + duration += pushZero(rx51device); + } + + ++i; + } + + return duration; +} + + +// This should be part of a general RC6 parent maybe? +int MCEProtocol::pushZero( + PIRRX51Hardware &rx51device) +{ + // Need to add a space, then a pulse. + int duration = 0; + + if (bufferContainsSpace) + { + // Merge this space and the previous one, and send to device: + rx51device.addSingle(buffer + biphaseUnit); + duration += (buffer + biphaseUnit); + buffer = 0; + bufferContainsSpace = false; + } + else + { + if (bufferContainsPulse) + { + // Flush out the buffer: + rx51device.addSingle(buffer); + duration += buffer; + buffer = 0; + bufferContainsPulse = false; + } + + // push a space onto the device: + rx51device.addSingle(biphaseUnit); + duration += biphaseUnit; + } + + // Put a pulse into the buffer to wait: + buffer = biphaseUnit; + bufferContainsPulse = true; + + return duration; +} + + +int MCEProtocol::pushOne( + PIRRX51Hardware &rx51device) +{ + // Need to add a pulse, then a space. + int duration = 0; + + // First, the pulse: + if (bufferContainsPulse) + { + rx51device.addSingle(buffer + biphaseUnit); + duration += (buffer + biphaseUnit); + buffer = 0; + bufferContainsPulse = false; + } + else + { + if (bufferContainsSpace) + { + // Flush the buffer: + rx51device.addSingle(buffer); + duration += buffer; + buffer = 0; + bufferContainsSpace = false; + } + // Now, add the pulse: + rx51device.addSingle(biphaseUnit); + duration += biphaseUnit; + } + + // Next, push a space onto the buffer: + buffer = biphaseUnit; + bufferContainsSpace = true; + + return duration; +} diff --git a/protocols/mceprotocol.h b/protocols/mceprotocol.h new file mode 100644 index 0000000..6f8dc24 --- /dev/null +++ b/protocols/mceprotocol.h @@ -0,0 +1,47 @@ +#ifndef MCEPROTOCOL_H +#define MCEPROTOCOL_H + +#include "pirprotocol.h" + +class PIRRX51Hardware; + +// +// The MCE protocol is derived from (but does not exactly match) RC6 mode 6A. +// + +class MCEProtocol: public PIRProtocol +{ +public: + MCEProtocol( + QObject *guiObject, + unsigned int index, + unsigned int oemData); + +public slots: + void startSendingCommand( + unsigned int threadableID, + PIRKeyName command); + +private: + int pushBits( + const CommandSequence &bits, + PIRRX51Hardware &device); + + int pushZero( + PIRRX51Hardware &device); + + int pushOne( + PIRRX51Hardware &device); + + unsigned int biphaseUnit; + + CommandSequence oemBits; + + unsigned int buffer; + int keypressCount; + + bool bufferContainsSpace; + bool bufferContainsPulse; +}; + +#endif // MCEPROTOCOL_H diff --git a/qtc_packaging/debian_fremantle/changelog b/qtc_packaging/debian_fremantle/changelog index c51b7de..f85d271 100644 --- a/qtc_packaging/debian_fremantle/changelog +++ b/qtc_packaging/debian_fremantle/changelog @@ -1,3 +1,17 @@ +pierogi (0.6.0) unstable; urgency=low + * My first candidate for Extras-Testing, so up to version 0.6 + * Fixed some bugs in Toshiba keysets + * Added MCE (Media Center Edition) remote keysets + + -- John Pietrzak Fri, 10 Feb 2012 11:08:18 -0500 + +pierogi (0.5.3) unstable; urgency=low + * Another "final" fix for the uninstall problem, this time for sure. :) + * Completely revamped Panasonic protocol, needs testing + * Created Bose keysets, added more Aiwa keysets + + -- John Pietrzak Wed, 08 Feb 2012 20:51:14 -0500 + pierogi (0.5.2) unstable; urgency=low * Finally, got a fix for the uninstall problem! * Some general internal cleanup. diff --git a/qtc_packaging/debian_fremantle/control b/qtc_packaging/debian_fremantle/control index 15ce426..2f000e4 100644 --- a/qtc_packaging/debian_fremantle/control +++ b/qtc_packaging/debian_fremantle/control @@ -11,8 +11,8 @@ Architecture: armel Depends: ${shlibs:Depends}, ${misc:Depends} Description: Universal Infrared Remote Control for N900 Pierogi is a Universal Infrared Remote Control app for the Nokia N900. It is independent from the LIRC server, and stores all configuration info internally. -XB-Maemo-Upgrade-Description: Continuing to work on installer - New method for creating pierogi.sudoers file should finally allow uninstaller to cleanly remove it. Also, completely revamped Panasonic keysets (possibly breaking them), and added Bose and more Aiwa keysets. +XB-Maemo-Upgrade-Description: First Extras-Testing Candidate + Pierogi is now somewhat stable, so I will start cleaning it up for submission to Extras-Testing. Also in this update, new MCE keysets, and cleanup of Toshiba keysets. XSBC-Bugtracker: https://garage.maemo.org/tracker/?func=add&group_id=2286&atid=7641 XB-Maemo-Display-Name: Pierogi XB-Maemo-Icon-26: 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 -- 1.7.9.5