From a3a01bd8980a5768b17ec060bd03322fb97ff417 Mon Sep 17 00:00:00 2001 From: Paolo Martino Date: Fri, 6 Sep 2013 10:04:50 +0200 Subject: [PATCH 1/4] Updated readme to explain the reasons for forking --- readme | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/readme b/readme index 3de652611..72d961833 100644 --- a/readme +++ b/readme @@ -1,3 +1,12 @@ +*** + +Forked to add XMP protocol, used in MySKY HD sat receivers/PVR by SKY Italia. +Actually, the remote is made by (or licenesed from) Universal Electroncis (http://www.uei.com), so the same protocol should work for many ohter devices (Comcast etc.). + +I found interesting details about the XMP protocol on the JP1 project wiki: http://www.hifi-remote.com/wiki/index.php?title=DecodeIR#XMP + +*** + This is the IRremote library for the Arduino. To download from github (http://github.com/shirriff/Arduino-IRremote), click on the "Downloads" link in the upper right, click "Download as zip", and get a zip file. Unzip it and rename the directory shirriff-Arduino-IRremote-nnn to IRremote From b06fcd1f36f1173888870d050dd9e162c98b0952 Mon Sep 17 00:00:00 2001 From: Paolo Martino Date: Fri, 6 Sep 2013 10:07:02 +0200 Subject: [PATCH 2/4] Updated readme to explain the reasons for forking --- readme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme b/readme index 72d961833..c0084d19a 100644 --- a/readme +++ b/readme @@ -1,6 +1,6 @@ *** -Forked to add XMP protocol, used in MySKY HD sat receivers/PVR by SKY Italia. +Forked to add the XMP protocol, used in MySKY HD sat receivers/PVR by SKY Italia. Actually, the remote is made by (or licenesed from) Universal Electroncis (http://www.uei.com), so the same protocol should work for many ohter devices (Comcast etc.). I found interesting details about the XMP protocol on the JP1 project wiki: http://www.hifi-remote.com/wiki/index.php?title=DecodeIR#XMP From 7ffe310f9b08818761269a83ad7e0376db413595 Mon Sep 17 00:00:00 2001 From: Paolo Martino Date: Mon, 9 Sep 2013 13:12:11 +0200 Subject: [PATCH 3/4] Added support for XMP protocol --- IRremote.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++++++++- IRremote.h | 11 ++++- IRremoteInt.h | 10 +++++ readme | 4 ++ 4 files changed, 131 insertions(+), 2 deletions(-) diff --git a/IRremote.cpp b/IRremote.cpp index ce7bb6d65..05705b64a 100644 --- a/IRremote.cpp +++ b/IRremote.cpp @@ -247,7 +247,7 @@ void IRsend::sendJVC(unsigned long data, int nbits, int repeat) void IRsend::sendRCMM(unsigned long data, int nbits) { enableIROut(36); - data = data << (32 - nbits); + data = data << (32 - nbits); mark(RCMM_HDR_MARK); space(RCMM_SPACE); for (int i = 0; i < nbits; i += 2) { @@ -259,6 +259,112 @@ void IRsend::sendRCMM(unsigned long data, int nbits) space(0); } +unsigned long IRsend::XMPSpaceLength(int value) +{ + return XMP_SPACE_BASE + value * XMP_SPACE_MULTIPLIER; +} + +short IRsend::XMPChecksum(short nibbles[]) +{ + int sum = 0; + + for (short i = 0; i < 8; i++) { + sum += nibbles[i]; + } + return (16 - (sum % 16)); +} + +void IRsend::sendXMP(unsigned long data, short repeat, short owner, short tag, unsigned long registry) +{ + enableIROut(38); + + int transmission[131]; + + short nibbles[8]; + short registry_packet[8]; + + /* + registry packet example: 0x2 0x3 0x0 0xF 0x4431 + nibble 0: owner + nibble 1: checksum + nibble 2: tag + nibble 3: XMP_REGISTRY_NIBBLE (fixed value: 0xF) + nibbles 4 to 7: registry number (manufacturer, product name, model etc.) + + */ + + nibbles[0] = owner; + nibbles[1] = 0; // placeholder for checksum + nibbles[2] = tag; + nibbles[3] = XMP_REGISTRY_NIBBLE; + for (short i = 0; i < 4; i++) { + nibbles[4 + i] = (registry >> 12 - (4 * i)) & 0xF; + } + nibbles[1] = XMPChecksum(nibbles); + memcpy (registry_packet, nibbles, sizeof (nibbles)); + + for (short i = 0; i < 8; i++) { + transmission[i] = XMPSpaceLength(registry_packet[i]); + } + + transmission[8] = XMP_PACKET_GAP; + + /* + data packet example: 0x2 0x4 0x0 0x0 0x5500 + nibble 0: owner + nibble 1: checksum + nibble 2: repeat flag (0x0 = first sending, 0x8 = subsequent sendings) + nibble 3: tag + nibbles 4 to 7: data + */ + + nibbles[1] = 0; + nibbles[3] = 0; + for (short i = 0; i < 4; i++) { + nibbles[4 + i] = (data >> 12 - (4 * i)) & 0xF; + } + + nibbles[1] = XMPChecksum(nibbles); + + for (short i = 0; i < 8; i++) { + transmission[9 + i] = XMPSpaceLength(nibbles[i]); + } + + transmission[17] = XMP_REPEAT_GAP; + + for (short i = 0; i < 8; i++) { + transmission[18 + i] = XMPSpaceLength(registry_packet[i]); + } + + transmission[26] = XMP_PACKET_GAP; + + /* + repeat packet example: 0x2 0xC 0x8 0x0 0x5500 + nibble 0: owner + nibble 1: checksum + nibble 2: repeat flag (0x0 = first sending, 0x8 = subsequent sendings) + nibble 3: tag + nibbles 4 to 7: data + */ + + nibbles[1] = 0; + nibbles[3] = XMP_REPEAT_NIBBLE; + for (short i = 0; i < 4; i++) { + nibbles[4 + i] = (data >> 12 - (4 * i)) & 0xF; + } + nibbles[1] = XMPChecksum(nibbles); + + for (short i = 0; i < 4; i++) { + transmission[27 + i] = XMPSpaceLength(nibbles[i]); + } + + for (short i = 0; i < 35; i++) { + mark(XMP_MARK); + space(transmission[i]); + } + +} + void IRsend::mark(int time) { // Sends an IR mark for the specified number of microseconds. // The mark output is modulated at the PWM frequency. diff --git a/IRremote.h b/IRremote.h index 58659138b..481cbbd15 100644 --- a/IRremote.h +++ b/IRremote.h @@ -41,7 +41,8 @@ SANYO, MITSUBISHI, RCMM, SAMSUNG, -KOGAN +KOGAN, +XMP }; // Results returned from the decoder @@ -81,6 +82,7 @@ class IRrecv long decodeJVC(decode_results *results); long decodeRCMM(decode_results *results); long decodeSamsung(decode_results *results); + long decodeXMP(decode_results *results); long decodeHash(decode_results *results); int compare(unsigned int oldval, unsigned int newval); @@ -112,10 +114,17 @@ class IRsend void sendSamsung(unsigned long data, int nbits); void sendRCMM(unsigned long data, int nbits); void sendJVC(unsigned long data, int nbits, int repeat); // *Note instead of sending the REPEAT constant if you want the JVC repeat signal sent, send the original code value and change the repeat argument from 0 to 1. JVC protocol repeats by skipping the header NOT by sending a separate code value like NEC does. + void sendXMP(unsigned long data, short repeat, short owner, short tag, unsigned long registry); + // private: void enableIROut(int khz); VIRTUAL void mark(int usec); VIRTUAL void space(int usec); + +private: + unsigned long XMPSpaceLength(int value); + short XMPChecksum(short nibbles[]); + }; // Some useful constants diff --git a/IRremoteInt.h b/IRremoteInt.h index 5200fa4d4..f567e8de0 100644 --- a/IRremoteInt.h +++ b/IRremoteInt.h @@ -174,6 +174,16 @@ #define RCMM_SPACE 277 #define RCMM_INCREMENT 167 +// XMP uses one burst pair to encode numbers 0 to 15, with an on duration of 210uS, and off duration of 760uS + n*136uS where n takes on values of 0 to 15 +// Gaps are empirically determined +#define XMP_MARK 210 +#define XMP_SPACE_BASE 760 +#define XMP_SPACE_MULTIPLIER 136 +#define XMP_PACKET_GAP 12320 +#define XMP_REPEAT_GAP 76920 +#define XMP_REPEAT_NIBBLE 0x8 +#define XMP_REGISTRY_NIBBLE 0xF + #define SHARP_BITS 15 #define DISH_BITS 16 diff --git a/readme b/readme index c0084d19a..dc73848e4 100644 --- a/readme +++ b/readme @@ -5,6 +5,10 @@ Actually, the remote is made by (or licenesed from) Universal Electroncis (http: I found interesting details about the XMP protocol on the JP1 project wiki: http://www.hifi-remote.com/wiki/index.php?title=DecodeIR#XMP +Starting off from those informations, I managed to reverse-engineer the protocol and everything seems to work fine, at least for the MySKY HD receiver. + +I'll publish some details of the reverse-engineering process on my blog as soon as I can. + *** This is the IRremote library for the Arduino. From 4a36d7ec369e1a4902d54e92ff516b6092f494e2 Mon Sep 17 00:00:00 2001 From: Paolo Martino Date: Mon, 9 Sep 2013 13:15:41 +0200 Subject: [PATCH 4/4] Code cleaning --- IRremote.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IRremote.cpp b/IRremote.cpp index 05705b64a..3df52ea83 100644 --- a/IRremote.cpp +++ b/IRremote.cpp @@ -261,7 +261,7 @@ void IRsend::sendRCMM(unsigned long data, int nbits) unsigned long IRsend::XMPSpaceLength(int value) { - return XMP_SPACE_BASE + value * XMP_SPACE_MULTIPLIER; + return XMP_SPACE_BASE + value * XMP_SPACE_MULTIPLIER; } short IRsend::XMPChecksum(short nibbles[])