فهرست منبع

[FL-1800] IRDA: enc/decoder refactoring, Add NEC42 (#705)

* WIP: IRDA: multilen protocol refactoring, NEC42
* IRDA: Refactoring encoder/decoder

Co-authored-by: あく <alleteam@gmail.com>
Albert Kharisov 4 سال پیش
والد
کامیت
4f233ff0a3

+ 7 - 10
applications/tests/irda_decoder_encoder/irda_decoder_encoder_test.c

@@ -129,10 +129,7 @@ static void run_encoder_decoder(const IrdaMessage input_messages[], uint32_t inp
         for(int i = 0; i < timings_len; ++i) {
             message_decoded = irda_decode(decoder_handler, level, timings[i]);
             if((i == timings_len - 2) && level && message_decoded) {
-                /* In case we end with space timing - message can be decoded at last mark.
-                 * Exception - SIRC protocol, which has variable message length (12/15/20),
-                 * and decoder recognizes protocol by silence time before next message
-                 * or by timeout (irda_check_decoder_ready()). */
+                /* In case we end with space timing - message can be decoded at last mark */
                 break;
             } else if(i < timings_len - 1) {
                 mu_check(!message_decoded);
@@ -225,17 +222,16 @@ MU_TEST(test_mix) {
     RUN_DECODER(test_decoder_rc6_input1, test_decoder_rc6_expected1);
     RUN_DECODER(test_decoder_necext_input1, test_decoder_necext_expected1);
     RUN_DECODER(test_decoder_sirc_input5, test_decoder_sirc_expected5);
+    RUN_DECODER(test_decoder_nec_input3, test_decoder_nec_expected3);
     RUN_DECODER(test_decoder_rc5_input5, test_decoder_rc5_expected5);
     RUN_DECODER(test_decoder_samsung32_input1, test_decoder_samsung32_expected1);
     RUN_DECODER(test_decoder_sirc_input3, test_decoder_sirc_expected3);
 }
 
-MU_TEST(test_decoder_nec1) {
+MU_TEST(test_decoder_nec) {
     RUN_DECODER(test_decoder_nec_input1, test_decoder_nec_expected1);
-}
-
-MU_TEST(test_decoder_nec2) {
     RUN_DECODER(test_decoder_nec_input2, test_decoder_nec_expected2);
+    RUN_DECODER(test_decoder_nec_input3, test_decoder_nec_expected3);
 }
 
 MU_TEST(test_decoder_unexpected_end_in_sequence) {
@@ -295,6 +291,8 @@ MU_TEST(test_encoder_rc6) {
 MU_TEST(test_encoder_decoder_all) {
     RUN_ENCODER_DECODER(test_nec);
     RUN_ENCODER_DECODER(test_necext);
+    RUN_ENCODER_DECODER(test_nec42);
+    RUN_ENCODER_DECODER(test_nec42ext);
     RUN_ENCODER_DECODER(test_samsung32);
     RUN_ENCODER_DECODER(test_rc6);
     RUN_ENCODER_DECODER(test_rc5);
@@ -312,8 +310,7 @@ MU_TEST_SUITE(test_irda_decoder_encoder) {
     MU_RUN_TEST(test_decoder_rc6);
     MU_RUN_TEST(test_encoder_rc6);
     MU_RUN_TEST(test_decoder_unexpected_end_in_sequence);
-    MU_RUN_TEST(test_decoder_nec1);
-    MU_RUN_TEST(test_decoder_nec2);
+    MU_RUN_TEST(test_decoder_nec);
     MU_RUN_TEST(test_decoder_samsung32);
     MU_RUN_TEST(test_decoder_necext1);
     MU_RUN_TEST(test_mix);

+ 96 - 0
applications/tests/irda_decoder_encoder/test_data/irda_nec_test_data.srcdata

@@ -178,6 +178,45 @@ const IrdaMessage test_decoder_nec_expected2[] = {
     {IrdaProtocolNEC,     0x00,      0x0A,   true},
 };
 
+const uint32_t test_decoder_nec_input3[] = {
+200000,         8862, 4452, 562, 563, 559, 1681, 563, 1646, 567, 586, 556, 569, 563, 583, 559, 571, 561, 1675, 559, 565, 567, 1673, 561, 561, 561, 592, 561, 565, 567, 579, 563, 567, 565, 584, 558, 1652, 561, 592, 561, 561, 561, 1679, 565, 560, 562, 584, 558, 1659, 564, 585, 557, 566, 566, 1675, 559, 1649, 564, 589, 564, 1649, 564, 1668, 566, 565, 567, 1669, 565,
+    43470,      8896, 4432, 561, 561, 561, 1679, 565, 1648, 565, 581, 561, 568, 564, 586, 567, 558, 564, 1676, 558, 564, 558, 1681, 563, 563, 559, 587, 566, 565, 567, 582, 561, 564, 558, 595, 558, 1650, 563, 590, 563, 563, 559, 1674, 560, 570, 562, 587, 566, 1645, 568, 586, 556, 565, 567, 1672, 562, 1651, 562, 584, 558, 1658, 566, 1671, 563, 561, 561, 1679, 565,
+200000,         8881, 4383, 569, 549, 573, 548, 574, 541, 571, 550, 572, 547, 575, 539, 573, 551, 571, 1651, 573, 545, 567, 554, 568, 548, 574, 1652, 572, 547, 575, 1645, 568, 1661, 573, 545, 567, 1657, 567, 554, 568, 547, 575, 1652, 572, 547, 575, 539, 573, 1657, 567, 550, 572, 545, 577, 1651, 573, 1648, 576, 545, 567, 1659, 575, 1645, 568, 555, 567, 1657, 567,
+    38995,      8883, 4369, 573, 543, 569, 552, 570, 549, 573, 541, 571, 553, 569, 548, 574, 543, 569, 1658, 566, 550, 572, 548, 574, 546, 566, 1653, 571, 553, 569, 1654, 570, 1654, 570, 551, 571, 1651, 573, 547, 575, 545, 567, 1653, 571, 552, 570, 547, 575, 1649, 564, 556, 566, 550, 572, 1655, 569, 1656, 568, 546, 566, 1664, 570, 1653, 571, 547, 565, 1663, 571,
+200000,         8987, 4504, 561, 593, 539, 589, 533, 596, 515, 586, 536, 592, 540, 588, 534, 595, 517, 1713, 541, 1664, 570, 1686, 558, 596, 515, 587, 535, 593, 539, 1691, 543, 1689, 565, 588, 513, 1691, 563, 1668, 617, 1613, 641, 1615, 567, 587, 535, 593, 519, 610, 512, 590, 542, 1714, 510, 593, 539, 1691, 563, 591, 510, 1720, 535, 594, 518, 584, 538, 591, 541,
+    39546,      8990, 4501, 565, 590, 542, 586, 536, 593, 508, 593, 539, 589, 543, 585, 537, 592, 509, 1720, 545, 1660, 615, 1642, 561, 567, 534, 594, 538, 590, 542, 1688, 535, 1696, 558, 595, 517, 1687, 567, 1664, 621, 1635, 619, 1611, 561, 594, 538, 590, 511, 617, 515, 586, 536, 1721, 513, 589, 543, 1687, 568, 587, 514, 1691, 563, 590, 511, 591, 541, 587, 535,
+200000,         8986, 4505, 560, 594, 538, 590, 542, 586, 515, 586, 536, 593, 539, 589, 533, 595, 517, 1714, 540, 587, 535, 594, 518, 1713, 542, 586, 515, 587, 535, 1722, 543, 1662, 562, 592, 540, 1664, 570, 585, 537, 591, 541, 1689, 545, 584, 538, 590, 542, 1688, 536, 593, 539, 589, 512, 590, 542, 586, 536, 1720, 514, 588, 544, 585, 537, 591, 541, 587, 514,
+    40671,      8986, 4505, 560, 594, 538, 590, 542, 586, 515, 587, 535, 593, 539, 589, 533, 595, 516, 1714, 541, 587, 535, 594, 518, 1712, 542, 586, 515, 587, 535, 1722, 543, 1662, 561, 592, 540, 1664, 570, 585, 537, 591, 541, 1689, 545, 584, 538, 590, 542, 1688, 536, 593, 539, 589, 512, 590, 542, 586, 536, 1720, 514, 588, 544, 585, 537, 591, 541, 587, 514,
+200000,         8990, 4500, 566, 1692, 562, 1668, 566, 588, 534, 594, 518, 584, 538, 591, 541, 587, 535, 1669, 565, 589, 543, 1688, 536, 592, 540, 1691, 563, 1667, 567, 1664, 621, 1635, 568, 586, 515, 587, 535, 593, 539, 589, 543, 1662, 562, 592, 540, 588, 534, 594, 518, 585, 537, 591, 541, 587, 514, 587, 535, 594, 538, 590, 542, 586, 515, 586, 536, 593, 539,
+    39544,      8993, 4498, 567, 1690, 564, 1666, 568, 586, 536, 593, 508, 593, 539, 589, 543, 585, 537, 1668, 566, 588, 544, 1687, 537, 591, 541, 1690, 564, 1666, 568, 1663, 561, 1696, 569, 585, 516, 586, 536, 593, 539, 589, 543, 1661, 562, 592, 540, 588, 534, 594, 517, 584, 538, 591, 541, 587, 514, 587, 535, 593, 539, 589, 543, 585, 516, 586, 536, 592, 540,
+200000,         8894, 4456, 589, 1676, 589, 571, 582, 574, 589, 571, 582, 1683, 582, 1677, 588, 1682, 583, 574, 589, 568, 585, 1682, 583, 1678, 587, 1680, 585, 574, 589, 565, 588, 575, 588, 1675, 590, 567, 586, 1681, 584, 571, 582, 1685, 590, 568, 585, 569, 584, 1685, 590, 567, 586, 1678, 587, 574, 589, 1672, 582, 578, 585, 1679, 586, 1674, 591, 572, 591, 1672, 582,
+    39632,      8912, 4464, 560, 1703, 562, 598, 565, 594, 559, 594, 559, 1711, 564, 1698, 567, 1697, 568, 593, 560, 595, 568, 1698, 567, 1698, 567, 1693, 561, 602, 561, 596, 567, 590, 563, 1704, 561, 594, 559, 1707, 568, 591, 562, 1697, 568, 596, 567, 590, 563, 1700, 565, 596, 567, 1693, 561, 599, 564, 1701, 564, 589, 564, 1706, 559, 1704, 561, 597, 566, 1700, 565,
+200000,         9018, 4500, 565, 1666, 568, 1689, 565, 588, 513, 1691, 615, 1616, 618, 1639, 564, 1667, 567, 587, 535, 594, 538, 563, 538, 590, 542, 586, 536, 593, 508, 593, 539, 589, 543, 1688, 535, 592, 540, 588, 544, 585, 537, 591, 510, 1694, 560, 1670, 564, 1693, 562, 1669, 565, 1692, 542, 1689, 565, 588, 534, 595, 517, 585, 537, 591, 541, 587, 535, 568, 544, 584, 538, 591, 541, 1663, 560, 1696, 569, 1662, 562, 1695, 539, 1692, 614, 1616, 566, 1691, 563, 1667, 567,
+    23184,      9012, 4505, 560, 1697, 537, 1693, 561, 593, 508, 1696, 569, 1662, 562, 1695, 560, 1671, 563, 591, 541, 587, 535, 594, 518, 584, 538, 590, 542, 586, 515, 613, 509, 593, 539, 1692, 542, 585, 537, 592, 540, 588, 534, 594, 518, 1687, 567, 1663, 560, 1697, 568, 1662, 562, 1695, 539, 1692, 563, 591, 541, 587, 514, 588, 544, 584, 538, 590, 542, 586, 515, 587, 535, 593, 539, 1666, 568, 1689, 565, 1665, 569, 1688, 536, 1695, 570, 1661, 562, 1694, 561, 1670, 564,
+200000,         8835, 4446, 537, 562, 539, 562, 539, 1663, 540, 1667, 536, 1669, 534, 560, 531, 573, 539, 559, 532, 1672, 531, 570, 531, 564, 537, 563, 538, 561, 540, 1660, 533, 1677, 536, 561, 540, 557, 534, 567, 534, 1668, 535, 1672, 531, 1675, 538, 555, 536, 1674, 539, 1665, 538, 1666, 537, 1671, 532, 563, 538, 1669, 534, 566, 535, 558, 533, 1677, 536, 562, 539, 558, 533, 568, 533, 1668, 535, 566, 535, 1670, 533, 1667, 536, 568, 533, 1671, 532, 1672, 531, 1676, 537,
+    22779,      8870, 4437, 535,
+    92592,      8861, 4414, 538,
+};
+
+const IrdaMessage test_decoder_nec_expected3[] = {
+    {IrdaProtocolNECext,    0x286,      0xB649,     false},
+    {IrdaProtocolNECext,    0x286,      0xB649,     false},
+    {IrdaProtocolNECext,    0x6880,     0xB649,     false},
+    {IrdaProtocolNECext,    0x6880,     0xB649,     false},
+    {IrdaProtocolNECext,    0x6380,     0x150F,     false},
+    {IrdaProtocolNECext,    0x6380,     0x150F,     false},
+    {IrdaProtocolNECext,    0x6480,     0x849,      false},
+    {IrdaProtocolNECext,    0x6480,     0x849,      false},
+    {IrdaProtocolNECext,    0x7A83,     0x8,        false},
+    {IrdaProtocolNECext,    0x7A83,     0x8,        false},
+    {IrdaProtocolNEC,       0x71,       0x4A,       false},
+    {IrdaProtocolNEC,       0x71,       0x4A,       false},
+    {IrdaProtocolNEC42,     0x7B,       0x0,        false},
+    {IrdaProtocolNEC42,     0x7B,       0x0,        false},
+    {IrdaProtocolNEC42,     0x11C,      0x12,       false},
+};
+
+
 const IrdaMessage test_nec[] = {
     {IrdaProtocolNEC,     0x00,      0x00,  false},
     {IrdaProtocolNEC,     0x01,      0x00,  false},
@@ -209,4 +248,61 @@ const IrdaMessage test_nec[] = {
     {IrdaProtocolNEC,     0x55,      0x55,  true},
 };
 
+const IrdaMessage test_nec42[] = {
+    {IrdaProtocolNEC42,     0x0000,      0x00,  false},
+    {IrdaProtocolNEC42,     0x0001,      0x00,  false},
+    {IrdaProtocolNEC42,     0x0001,      0x80,  false},
+    {IrdaProtocolNEC42,     0x0000,      0x80,  false},
+    {IrdaProtocolNEC42,     0x0000,      0x00,  false},
+    {IrdaProtocolNEC42,     0x0000,      0x00,  true},
+    {IrdaProtocolNEC42,     0x0000,      0x00,  false},
+    {IrdaProtocolNEC42,     0x0000,      0x00,  true},
+    {IrdaProtocolNEC42,     0x1FFF,      0xFF,  false},
+    {IrdaProtocolNEC42,     0x1FFE,      0xFF,  false},
+    {IrdaProtocolNEC42,     0x1FFE,      0x7F,  false},
+    {IrdaProtocolNEC42,     0x1FFF,      0x7F,  false},
+    {IrdaProtocolNEC42,     0x1FFF,      0xFF,  false},
+    {IrdaProtocolNEC42,     0x1FFF,      0xFF,  true},
+    {IrdaProtocolNEC42,     0x0AAA,      0x55,  false},
+    {IrdaProtocolNEC42,     0x1555,      0xAA,  false},
+    {IrdaProtocolNEC42,     0x1555,      0x55,  false},
+    {IrdaProtocolNEC42,     0x0AAA,      0xAA,  false},
+    {IrdaProtocolNEC42,     0x0AAA,      0xAA,  true},
+    {IrdaProtocolNEC42,     0x0AAA,      0xAA,  false},
+    {IrdaProtocolNEC42,     0x0AAA,      0xAA,  true},
+    {IrdaProtocolNEC42,     0x0AAA,      0xAA,  true},
+    {IrdaProtocolNEC42,     0x1555,      0x55,  false},
+    {IrdaProtocolNEC42,     0x1555,      0x55,  true},
+    {IrdaProtocolNEC42,     0x1555,      0x55,  true},
+    {IrdaProtocolNEC42,     0x1555,      0x55,  true},
+};
+
+const IrdaMessage test_nec42ext[] = {
+    {IrdaProtocolNEC42ext,     0x0000000,      0x0000,  false},
+    {IrdaProtocolNEC42ext,     0x0000001,      0x0000,  false},
+    {IrdaProtocolNEC42ext,     0x0000001,      0x8000,  false},
+    {IrdaProtocolNEC42ext,     0x0000000,      0x8000,  false},
+    {IrdaProtocolNEC42ext,     0x0000000,      0x0000,  false},
+    {IrdaProtocolNEC42ext,     0x0000000,      0x0000,  true},
+    {IrdaProtocolNEC42ext,     0x0000000,      0x0000,  false},
+    {IrdaProtocolNEC42ext,     0x0000000,      0x0000,  true},
+    {IrdaProtocolNEC42ext,     0x3F000FF,      0xF00F,  false},
+    {IrdaProtocolNEC42ext,     0x3F000FE,      0xF00F,  false},
+    {IrdaProtocolNEC42ext,     0x3F000FE,      0x700F,  false},
+    {IrdaProtocolNEC42ext,     0x3F000FF,      0x700F,  false},
+    {IrdaProtocolNEC42ext,     0x3F000FF,      0xF00F,  false},
+    {IrdaProtocolNEC42ext,     0x3F000FF,      0xF00F,  true},
+    {IrdaProtocolNEC42ext,     0x2AAAAAA,      0x5555,  false},
+    {IrdaProtocolNEC42ext,     0x1555555,      0xAAAA,  false},
+    {IrdaProtocolNEC42ext,     0x1555555,      0x5555,  false},
+    {IrdaProtocolNEC42ext,     0x2AAAAAA,      0xAAAA,  false},
+    {IrdaProtocolNEC42ext,     0x2AAAAAA,      0xAAAA,  true},
+    {IrdaProtocolNEC42ext,     0x2AAAAAA,      0xAAAA,  false},
+    {IrdaProtocolNEC42ext,     0x2AAAAAA,      0xAAAA,  true},
+    {IrdaProtocolNEC42ext,     0x2AAAAAA,      0xAAAA,  true},
+    {IrdaProtocolNEC42ext,     0x1555555,      0x5555,  false},
+    {IrdaProtocolNEC42ext,     0x1555555,      0x5555,  true},
+    {IrdaProtocolNEC42ext,     0x1555555,      0x5555,  true},
+    {IrdaProtocolNEC42ext,     0x1555555,      0x5555,  true},
+};
 

+ 134 - 136
applications/tests/irda_decoder_encoder/test_data/irda_necext_test_data.srcdata

@@ -111,147 +111,145 @@ const uint32_t test_decoder_necext_input1[] = {
 };
 
 const IrdaMessage test_decoder_necext_expected1[] = {
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  false},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
-    {IrdaProtocolNECext,     0x7984,    0x12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  false},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
+    {IrdaProtocolNECext,     0x7984,    0xed12,  true},
 };
 
-
-
 const IrdaMessage test_necext[] = {
-    {IrdaProtocolNECext,     0x0000,      0x00,  false},
-    {IrdaProtocolNECext,     0x0001,      0x00,  false},
-    {IrdaProtocolNECext,     0x0001,      0x80,  false},
-    {IrdaProtocolNECext,     0x0000,      0x80,  false},
-    {IrdaProtocolNECext,     0x0000,      0x00,  false},
-    {IrdaProtocolNECext,     0x0000,      0x00,  true},
-    {IrdaProtocolNECext,     0x0000,      0x00,  false},
-    {IrdaProtocolNECext,     0x0000,      0x00,  true},
-    {IrdaProtocolNECext,     0xFFFF,      0xFF,  false},
-    {IrdaProtocolNECext,     0xFFFE,      0xFF,  false},
-    {IrdaProtocolNECext,     0xFFFE,      0x7F,  false},
-    {IrdaProtocolNECext,     0xFFFF,      0x7F,  false},
-    {IrdaProtocolNECext,     0xFFFF,      0xFF,  false},
-    {IrdaProtocolNECext,     0xFFFF,      0xFF,  true},
-    {IrdaProtocolNECext,     0xAAAA,      0x55,  false},
-    {IrdaProtocolNECext,     0x5555,      0xAA,  false},
-    {IrdaProtocolNECext,     0x5555,      0x55,  false},
-    {IrdaProtocolNECext,     0xAAAA,      0xAA,  false},
-    {IrdaProtocolNECext,     0xAAAA,      0xAA,  true},
+    {IrdaProtocolNECext,     0x0000,      0x0000,  false},
+    {IrdaProtocolNECext,     0x0001,      0x0000,  false},
+    {IrdaProtocolNECext,     0x0001,      0x8000,  false},
+    {IrdaProtocolNECext,     0x0000,      0x8000,  false},
+    {IrdaProtocolNECext,     0x0000,      0x0000,  false},
+    {IrdaProtocolNECext,     0x0000,      0x0000,  true},
+    {IrdaProtocolNECext,     0x0000,      0x0000,  false},
+    {IrdaProtocolNECext,     0x0000,      0x0000,  true},
+    {IrdaProtocolNECext,     0xFFFF,      0xFFFF,  false},
+    {IrdaProtocolNECext,     0xFFFE,      0xFFFF,  false},
+    {IrdaProtocolNECext,     0xFFFE,      0x7FFF,  false},
+    {IrdaProtocolNECext,     0xFFFF,      0x7FFF,  false},
+    {IrdaProtocolNECext,     0xFFFF,      0xFFFF,  false},
+    {IrdaProtocolNECext,     0xFFFF,      0xFFFF,  true},
+    {IrdaProtocolNECext,     0xAAAA,      0x5555,  false},
+    {IrdaProtocolNECext,     0x5555,      0xAAAA,  false},
+    {IrdaProtocolNECext,     0x5555,      0x5555,  false},
+    {IrdaProtocolNECext,     0xAAAA,      0xAAAA,  false},
+    {IrdaProtocolNECext,     0xAAAA,      0xAAAA,  true},
 
-    {IrdaProtocolNECext,     0xAAAA,      0xAA,  false},
-    {IrdaProtocolNECext,     0xAAAA,      0xAA,  true},
-    {IrdaProtocolNECext,     0xAAAA,      0xAA,  true},
+    {IrdaProtocolNECext,     0xAAAA,      0xAAAA,  false},
+    {IrdaProtocolNECext,     0xAAAA,      0xAAAA,  true},
+    {IrdaProtocolNECext,     0xAAAA,      0xAAAA,  true},
 
-    {IrdaProtocolNECext,     0x5555,      0x55,  false},
-    {IrdaProtocolNECext,     0x5555,      0x55,  true},
-    {IrdaProtocolNECext,     0x5555,      0x55,  true},
-    {IrdaProtocolNECext,     0x5555,      0x55,  true},
+    {IrdaProtocolNECext,     0x5555,      0x5555,  false},
+    {IrdaProtocolNECext,     0x5555,      0x5555,  true},
+    {IrdaProtocolNECext,     0x5555,      0x5555,  true},
+    {IrdaProtocolNECext,     0x5555,      0x5555,  true},
 };
 
 

+ 4 - 10
applications/tests/irda_decoder_encoder/test_data/irda_sirc_test_data.srcdata

@@ -426,20 +426,14 @@ const IrdaMessage test_decoder_sirc_expected5[] = {
     {IrdaProtocolSIRC20, 0xFB5, 0x53, false},
 };
 
-
-
-
 const IrdaMessage test_encoder_sirc_input1[] = {
     {IrdaProtocolSIRC, 0xA, 0x55, false},
 };
 
 const uint32_t test_encoder_sirc_expected1[] = {
-10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600,
+10000, 2400, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 600,
 };
 
-
-
-
 const IrdaMessage test_encoder_sirc_input2[] = {
     {IrdaProtocolSIRC15, 0x7D, 0x53, false},
     {IrdaProtocolSIRC15, 0x7D, 0x53, true},
@@ -447,9 +441,9 @@ const IrdaMessage test_encoder_sirc_input2[] = {
 };
 
 const uint32_t test_encoder_sirc_expected2[] = {
-    10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, /* 2 low levels in row */
-    18000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600, /* 2 low levels in row */
-    18000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600, 600,
+    10000, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600,
+    18600, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600,
+    18600, 2400, 600, 1200, 600, 1200, 600, 600, 600, 600, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 600, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 1200, 600, 600,
 };
 
 const IrdaMessage test_sirc[] = {

+ 111 - 129
lib/irda/encoder_decoder/common/irda_common_decoder.c

@@ -1,4 +1,5 @@
 #include "furi/check.h"
+#include "furi/common_defines.h"
 #include "irda.h"
 #include "irda_common_i.h"
 #include <stdbool.h>
@@ -39,11 +40,12 @@ static bool irda_check_preamble(IrdaCommonDecoder* decoder) {
     bool result = false;
     bool start_level = (decoder->level + decoder->timings_cnt + 1) % 2;
 
+    if (decoder->timings_cnt == 0)
+        return false;
+
     // align to start at Mark timing
     if (!start_level) {
-        if (decoder->timings_cnt > 0) {
-            decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1);
-        }
+        decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1);
     }
 
     if (decoder->protocol->timings.preamble_mark == 0) {
@@ -66,45 +68,75 @@ static bool irda_check_preamble(IrdaCommonDecoder* decoder) {
     return result;
 }
 
-/* Pulse Distance Modulation */
-IrdaStatus irda_common_decode_pdm(IrdaCommonDecoder* decoder) {
+
+/**
+ * decoder->protocol->databit_len[0] contains biggest amount of bits, for this protocol.
+ * decoder->protocol->databit_len[1...] contains lesser values, but which can be decoded
+ * for some protocol modifications.
+ */
+static IrdaStatus irda_common_decode_bits(IrdaCommonDecoder* decoder) {
     furi_assert(decoder);
 
-    uint32_t* timings = decoder->timings;
-    IrdaStatus status = IrdaStatusError;
+    IrdaStatus status = IrdaStatusOk;
+    const IrdaTimings* timings = &decoder->protocol->timings;
+
+    while (decoder->timings_cnt && (status == IrdaStatusOk)) {
+        bool level = (decoder->level + decoder->timings_cnt + 1) % 2;
+        uint32_t timing = decoder->timings[0];
+
+        /* check if short protocol version can be decoded */
+        if (timings->min_split_time && !level && (timing > timings->min_split_time)) {
+            for (int i = 1; decoder->protocol->databit_len[i] && (i < COUNT_OF(decoder->protocol->databit_len)); ++i) {
+                if (decoder->protocol->databit_len[i] == decoder->databit_cnt) {
+                    return IrdaStatusReady;
+                }
+            }
+        }
+
+        status = decoder->protocol->decode(decoder, level, timing);
+        furi_assert(status == IrdaStatusError || status == IrdaStatusOk);
+        if (status == IrdaStatusError) {
+            break;
+        }
+        decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1);
+
+        /* check if largest protocol version can be decoded */
+        if (level && (decoder->protocol->databit_len[0] == decoder->databit_cnt)) {
+            status = IrdaStatusReady;
+            break;
+        }
+    }
+
+    return status;
+}
+
+/* Pulse Distance-Width Modulation */
+IrdaStatus irda_common_decode_pdwm(IrdaCommonDecoder* decoder, bool level, uint32_t timing) {
+    furi_assert(decoder);
+
+    IrdaStatus status = IrdaStatusOk;
     uint32_t bit_tolerance = decoder->protocol->timings.bit_tolerance;
     uint16_t bit1_mark = decoder->protocol->timings.bit1_mark;
     uint16_t bit1_space = decoder->protocol->timings.bit1_space;
     uint16_t bit0_mark = decoder->protocol->timings.bit0_mark;
     uint16_t bit0_space = decoder->protocol->timings.bit0_space;
 
-    while (1) {
-        // Stop bit
-        if ((decoder->databit_cnt == decoder->protocol->databit_len) && (decoder->timings_cnt == 1)) {
-            if (MATCH_TIMING(timings[0], bit1_mark, bit_tolerance)) {
-                decoder->timings_cnt = 0;
-                status = IrdaStatusReady;
-            } else {
-                status = IrdaStatusError;
-            }
-            break;
-        }
+    bool analyze_timing = level ^ (bit1_mark == bit0_mark);
+    uint16_t bit1 = level ? bit1_mark : bit1_space;
+    uint16_t bit0 = level ? bit0_mark : bit0_space;
+    uint16_t no_info_timing = (bit1_mark == bit0_mark) ? bit1_mark : bit1_space;
 
-        if (decoder->timings_cnt >= 2) {
-            if (MATCH_TIMING(timings[0], bit1_mark, bit_tolerance)
-                && MATCH_TIMING(timings[1], bit1_space, bit_tolerance)) {
-                accumulate_lsb(decoder, 1);
-            } else if (MATCH_TIMING(timings[0], bit0_mark, bit_tolerance)
-                && MATCH_TIMING(timings[1], bit0_space, bit_tolerance)) {
-                accumulate_lsb(decoder, 0);
-            } else {
-                status = IrdaStatusError;
-                break;
-            }
-            decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 2);
+    if (analyze_timing) {
+        if (MATCH_TIMING(timing, bit1, bit_tolerance)) {
+            accumulate_lsb(decoder, 1);
+        } else if (MATCH_TIMING(timing, bit0, bit_tolerance)) {
+            accumulate_lsb(decoder, 0);
         } else {
-            status = IrdaStatusOk;
-            break;
+            status = IrdaStatusError;
+        }
+    } else {
+        if (!MATCH_TIMING(timing, no_info_timing, bit_tolerance)) {
+            status = IrdaStatusError;
         }
     }
 
@@ -112,111 +144,59 @@ IrdaStatus irda_common_decode_pdm(IrdaCommonDecoder* decoder) {
 }
 
 /* level switch detection goes in middle of time-quant */
-IrdaStatus irda_common_decode_manchester(IrdaCommonDecoder* decoder) {
+IrdaStatus irda_common_decode_manchester(IrdaCommonDecoder* decoder, bool level, uint32_t timing) {
     furi_assert(decoder);
-    IrdaStatus status = IrdaStatusOk;
     uint16_t bit = decoder->protocol->timings.bit1_mark;
     uint16_t tolerance = decoder->protocol->timings.bit_tolerance;
 
-    while (decoder->timings_cnt) {
-        uint32_t timing = decoder->timings[0];
-        bool* switch_detect = &decoder->switch_detect;
-        furi_assert((*switch_detect == true) || (*switch_detect == false));
+    bool* switch_detect = &decoder->switch_detect;
+    furi_assert((*switch_detect == true) || (*switch_detect == false));
 
-        bool single_timing = MATCH_TIMING(timing, bit, tolerance);
-        bool double_timing = MATCH_TIMING(timing, 2*bit, tolerance);
+    bool single_timing = MATCH_TIMING(timing, bit, tolerance);
+    bool double_timing = MATCH_TIMING(timing, 2*bit, tolerance);
 
-        if(!single_timing && !double_timing) {
-            status = IrdaStatusError;
-            break;
-        }
+    if(!single_timing && !double_timing) {
+        return IrdaStatusError;
+    }
 
-        if ((decoder->protocol->manchester_start_from_space) && (decoder->databit_cnt == 0)) {
-            *switch_detect = 1; /* fake as we were previously in the middle of time-quant */
-            decoder->data[0] = 0;   /* first captured timing should be Mark */
-            ++decoder->databit_cnt;
-        }
+    if (decoder->protocol->manchester_start_from_space && (decoder->databit_cnt == 0)) {
+        *switch_detect = 1; /* fake as we were previously in the middle of time-quant */
+        accumulate_lsb(decoder, 0);
+    }
 
-        if (*switch_detect == 0) {
-            if (double_timing) {
-                status = IrdaStatusError;
-                break;
-            }
-            /* only single timing - level switch required in the middle of time-quant */
-            *switch_detect = 1;
-        } else {
-            /* double timing means we in the middle of time-quant again */
-            if (single_timing)
-                *switch_detect = 0;
+    if (*switch_detect == 0) {
+        if (double_timing) {
+            return IrdaStatusError;
         }
+        /* only single timing - level switch required in the middle of time-quant */
+        *switch_detect = 1;
+    } else {
+        /* double timing means we're in the middle of time-quant again */
+        if (single_timing)
+            *switch_detect = 0;
+    }
 
-        decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1);
-        status = IrdaStatusOk;
-        bool level = (decoder->level + decoder->timings_cnt) % 2;
-
-        if (decoder->databit_cnt < decoder->protocol->databit_len) {
-            if (*switch_detect) {
-                accumulate_lsb(decoder, level);
-            }
-            if (decoder->databit_cnt == decoder->protocol->databit_len) {
-                if (level) {
-                    status = IrdaStatusReady;
-                    break;
-                }
-            }
-        } else {
-            furi_assert(level);
-            /* cover case: sequence should be stopped after last bit was received */
-            if (single_timing) {
-                status = IrdaStatusReady;
-                break;
-            } else {
-                status = IrdaStatusError;
-            }
-        }
+    if (*switch_detect) {
+        accumulate_lsb(decoder, level);
     }
 
-    return status;
+    return IrdaStatusOk;
 }
 
-/* Pulse Width Modulation */
-IrdaStatus irda_common_decode_pwm(IrdaCommonDecoder* decoder) {
-    furi_assert(decoder);
+IrdaMessage* irda_common_decoder_check_ready(IrdaCommonDecoder* decoder) {
+    IrdaMessage* message = NULL;
 
-    uint32_t* timings = decoder->timings;
-    IrdaStatus status = IrdaStatusOk;
-    uint32_t bit_tolerance = decoder->protocol->timings.bit_tolerance;
-    uint16_t bit1_mark = decoder->protocol->timings.bit1_mark;
-    uint16_t bit1_space = decoder->protocol->timings.bit1_space;
-    uint16_t bit0_mark = decoder->protocol->timings.bit0_mark;
-
-    while (decoder->timings_cnt) {
-        bool level = (decoder->level + decoder->timings_cnt + 1) % 2;
-
-        if (level) {
-            if (MATCH_TIMING(timings[0], bit1_mark, bit_tolerance)) {
-                accumulate_lsb(decoder, 1);
-            } else if (MATCH_TIMING(timings[0], bit0_mark, bit_tolerance)) {
-                accumulate_lsb(decoder, 0);
-            } else {
-                status = IrdaStatusError;
-                break;
-            }
+    if (decoder->protocol->interpret(decoder)) {
+        decoder->databit_cnt = 0;
+        message = &decoder->message;
+        if (decoder->protocol->decode_repeat) {
+            decoder->state = IrdaCommonDecoderStateProcessRepeat;
         } else {
-            if (!MATCH_TIMING(timings[0], bit1_space, bit_tolerance)) {
-                status = IrdaStatusError;
-                break;
-            }
-        }
-        decoder->timings_cnt = consume_samples(decoder->timings, decoder->timings_cnt, 1);
-
-        if (decoder->databit_cnt == decoder->protocol->databit_len) {
-            status = IrdaStatusReady;
-            break;
+            decoder->state = IrdaCommonDecoderStateWaitPreamble;
         }
     }
 
-    return status;
+    return message;
 }
 
 IrdaMessage* irda_common_decode(IrdaCommonDecoder* decoder, bool level, uint32_t duration) {
@@ -245,12 +225,13 @@ IrdaMessage* irda_common_decode(IrdaCommonDecoder* decoder, bool level, uint32_t
             }
             break;
         case IrdaCommonDecoderStateDecode:
-            status = decoder->protocol->decode(decoder);
+            status = irda_common_decode_bits(decoder);
             if (status == IrdaStatusReady) {
-                if (decoder->protocol->interpret(decoder)) {
-                    message = &decoder->message;
-                    decoder->state = IrdaCommonDecoderStateProcessRepeat;
-                } else {
+                message = irda_common_decoder_check_ready(decoder);
+                if (message) {
+                    continue;
+                } else if (decoder->protocol->databit_len[0] == decoder->databit_cnt) {
+                    /* error: can't decode largest protocol - begin decoding from start */
                     decoder->state = IrdaCommonDecoderStateWaitPreamble;
                 }
             } else if (status == IrdaStatusError) {
@@ -259,10 +240,6 @@ IrdaMessage* irda_common_decode(IrdaCommonDecoder* decoder, bool level, uint32_t
             }
             break;
         case IrdaCommonDecoderStateProcessRepeat:
-            if (!decoder->protocol->decode_repeat) {
-                decoder->state = IrdaCommonDecoderStateWaitPreamble;
-                continue;
-            }
             status = decoder->protocol->decode_repeat(decoder);
             if (status == IrdaStatusError) {
                 irda_common_decoder_reset_state(decoder);
@@ -282,9 +259,14 @@ IrdaMessage* irda_common_decode(IrdaCommonDecoder* decoder, bool level, uint32_t
 void* irda_common_decoder_alloc(const IrdaCommonProtocolSpec* protocol) {
     furi_assert(protocol);
 
+    /* protocol->databit_len[0] has to contain biggest value of bits that can be decoded */
+    for (int i = 1; i < COUNT_OF(protocol->databit_len); ++i) {
+        furi_assert(protocol->databit_len[i] <= protocol->databit_len[0]);
+    }
+
     uint32_t alloc_size = sizeof(IrdaCommonDecoder)
-                          + protocol->databit_len / 8
-                          + !!(protocol->databit_len % 8);
+                          + protocol->databit_len[0] / 8
+                          + !!(protocol->databit_len[0] % 8);
     IrdaCommonDecoder* decoder = furi_alloc(alloc_size);
     memset(decoder, 0, alloc_size);
     decoder->protocol = protocol;

+ 43 - 32
lib/irda/encoder_decoder/common/irda_common_encoder.c

@@ -4,6 +4,19 @@
 #include <stdbool.h>
 #include <furi.h>
 #include "irda_i.h"
+#include <stdint.h>
+
+static IrdaStatus irda_common_encode_bits(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level) {
+    IrdaStatus status = encoder->protocol->encode(encoder, duration, level);
+    furi_assert(status == IrdaStatusOk);
+    ++encoder->timings_encoded;
+    encoder->timings_sum += *duration;
+    if ((encoder->bits_encoded == encoder->bits_to_encode) && *level) {
+        status = IrdaStatusDone;
+    }
+
+    return status;
+}
 
 /*
  *
@@ -32,14 +45,12 @@ IrdaStatus irda_common_encode_manchester(IrdaCommonEncoder* encoder, uint32_t* d
 
     *level = even_timing ^ logic_value;
     *duration = timings->bit1_mark;
-    if (even_timing)        /* start encoding from space */
+    if (even_timing)
         ++encoder->bits_encoded;
-    ++encoder->timings_encoded;
-    encoder->timings_sum += *duration;
+    else if (*level && (encoder->bits_encoded + 1 == encoder->bits_to_encode))
+        ++encoder->bits_encoded;        /* don't encode last space */
 
-    bool finish = (encoder->bits_encoded == encoder->protocol->databit_len);
-    finish |= (encoder->bits_encoded == (encoder->protocol->databit_len-1)) && *level && !even_timing;
-    return finish ? IrdaStatusDone : IrdaStatusOk;
+    return IrdaStatusOk;
 }
 
 IrdaStatus irda_common_encode_pdwm(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level) {
@@ -47,39 +58,25 @@ IrdaStatus irda_common_encode_pdwm(IrdaCommonEncoder* encoder, uint32_t* duratio
     furi_assert(duration);
     furi_assert(level);
 
-    bool done = false;
     const IrdaTimings* timings = &encoder->protocol->timings;
     uint8_t index = encoder->bits_encoded / 8;
     uint8_t shift = encoder->bits_encoded % 8;   // LSB first
     bool logic_value = !!(encoder->data[index] & (0x01 << shift));
-
-    // stop bit
-    if (encoder->bits_encoded == encoder->protocol->databit_len) {
-        furi_assert(!encoder->protocol->no_stop_bit);
-        *duration = timings->bit1_mark;
-        *level = true;
-        ++encoder->timings_encoded;
-        encoder->timings_sum += *duration;
-        return IrdaStatusDone;
-    }
+    bool pwm = timings->bit1_space == timings->bit0_space;
 
     if (encoder->timings_encoded % 2) {         /* start encoding from space */
         *duration = logic_value ? timings->bit1_mark : timings->bit0_mark;
         *level = true;
+        if (pwm)
+            ++encoder->bits_encoded;
     } else {
         *duration = logic_value ? timings->bit1_space : timings->bit0_space;
         *level = false;
-        ++encoder->bits_encoded;
-    }
-
-    if ((encoder->bits_encoded == encoder->protocol->databit_len)
-        && encoder->protocol->no_stop_bit) {
-        done = true;
+        if (!pwm)
+            ++encoder->bits_encoded;
     }
 
-    ++encoder->timings_encoded;
-    encoder->timings_sum += *duration;
-    return done ? IrdaStatusDone : IrdaStatusOk;
+    return IrdaStatusOk;
 }
 
 IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level) {
@@ -116,7 +113,7 @@ IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bo
         }
         /* FALLTHROUGH */
     case IrdaCommonEncoderStateEncode:
-        status = encoder->protocol->encode(encoder, duration, level);
+        status = irda_common_encode_bits(encoder, duration, level);
         if (status == IrdaStatusDone) {
             if (encoder->protocol->encode_repeat) {
                 encoder->state = IrdaCommonEncoderStateEncodeRepeat;
@@ -138,10 +135,18 @@ IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bo
 
 void* irda_common_encoder_alloc(const IrdaCommonProtocolSpec* protocol) {
     furi_assert(protocol);
+    if (protocol->decode == irda_common_decode_pdwm) {
+        furi_assert((protocol->timings.bit1_mark == protocol->timings.bit0_mark) ^ (protocol->timings.bit1_space == protocol->timings.bit0_space));
+    }
+
+    /* protocol->databit_len[0] has to contain biggest value of bits that can be decoded */
+    for (int i = 1; i < COUNT_OF(protocol->databit_len); ++i) {
+        furi_assert(protocol->databit_len[i] <= protocol->databit_len[0]);
+    }
 
-    uint32_t alloc_size = sizeof(IrdaCommonEncoder)
-                          + protocol->databit_len / 8
-                          + !!(protocol->databit_len % 8);
+    uint32_t alloc_size = sizeof(IrdaCommonDecoder)
+                          + protocol->databit_len[0] / 8
+                          + !!(protocol->databit_len[0] % 8);
     IrdaCommonEncoder* encoder = furi_alloc(alloc_size);
     memset(encoder, 0, alloc_size);
     encoder->protocol = protocol;
@@ -162,8 +167,14 @@ void irda_common_encoder_reset(IrdaCommonEncoder* encoder) {
     encoder->state = IrdaCommonEncoderStateSilence;
     encoder->switch_detect = 0;
 
-    uint8_t bytes_to_clear = encoder->protocol->databit_len / 8
-        + !!(encoder->protocol->databit_len % 8);
+    uint8_t max_databit_len = 0;
+
+    for (int i = 0; i < COUNT_OF(encoder->protocol->databit_len); ++i) {
+        max_databit_len = MAX(max_databit_len, encoder->protocol->databit_len[i]);
+    }
+
+    uint8_t bytes_to_clear = max_databit_len / 8
+        + !!(max_databit_len % 8);
     memset(encoder->data, 0, bytes_to_clear);
 }
 

+ 9 - 7
lib/irda/encoder_decoder/common/irda_common_i.h

@@ -11,7 +11,8 @@
 typedef struct IrdaCommonDecoder IrdaCommonDecoder;
 typedef struct IrdaCommonEncoder IrdaCommonEncoder;
 
-typedef IrdaStatus (*IrdaCommonDecode)(IrdaCommonDecoder*);
+typedef IrdaStatus (*IrdaCommonDecode)(IrdaCommonDecoder*, bool, uint32_t);
+typedef IrdaStatus (*IrdaCommonDecodeRepeat)(IrdaCommonDecoder*);
 typedef bool (*IrdaCommonInterpret)(IrdaCommonDecoder*);
 typedef IrdaStatus (*IrdaCommonEncode)(IrdaCommonEncoder* encoder, uint32_t* out, bool* polarity);
 
@@ -19,9 +20,9 @@ typedef struct {
     IrdaTimings timings;
     bool     manchester_start_from_space;
     bool     no_stop_bit;
-    uint32_t databit_len;
+    uint8_t  databit_len[4];
     IrdaCommonDecode decode;
-    IrdaCommonDecode decode_repeat;
+    IrdaCommonDecodeRepeat decode_repeat;
     IrdaCommonInterpret interpret;
     IrdaCommonEncode encode;
     IrdaCommonEncode encode_repeat;
@@ -57,7 +58,8 @@ struct IrdaCommonEncoder {
     const IrdaCommonProtocolSpec* protocol;
     IrdaCommonStateEncoder state;
     bool switch_detect;
-    uint32_t bits_encoded;
+    uint8_t bits_to_encode;
+    uint8_t bits_encoded;
     uint32_t timings_sum;
     uint32_t timings_encoded;
     void* context;
@@ -65,12 +67,12 @@ struct IrdaCommonEncoder {
 };
 
 IrdaMessage* irda_common_decode(IrdaCommonDecoder *decoder, bool level, uint32_t duration);
-IrdaStatus irda_common_decode_pdm(IrdaCommonDecoder* decoder);
-IrdaStatus irda_common_decode_pwm(IrdaCommonDecoder* decoder);
-IrdaStatus irda_common_decode_manchester(IrdaCommonDecoder* decoder);
+IrdaStatus irda_common_decode_pdwm(IrdaCommonDecoder* decoder, bool level, uint32_t timing);
+IrdaStatus irda_common_decode_manchester(IrdaCommonDecoder* decoder, bool level, uint32_t timing);
 void* irda_common_decoder_alloc(const IrdaCommonProtocolSpec *protocol);
 void irda_common_decoder_free(IrdaCommonDecoder* decoder);
 void irda_common_decoder_reset(IrdaCommonDecoder* decoder);
+IrdaMessage* irda_common_decoder_check_ready(IrdaCommonDecoder* decoder);
 
 IrdaStatus irda_common_encode(IrdaCommonEncoder* encoder, uint32_t* duration, bool* polarity);
 IrdaStatus irda_common_encode_pdwm(IrdaCommonEncoder* encoder, uint32_t* duration, bool* polarity);

+ 13 - 8
lib/irda/encoder_decoder/common/irda_common_protocol_defs.c

@@ -12,10 +12,12 @@ const IrdaCommonProtocolSpec protocol_nec = {
         .preamble_tolerance = IRDA_NEC_PREAMBLE_TOLERANCE,
         .bit_tolerance = IRDA_NEC_BIT_TOLERANCE,
         .silence_time = IRDA_NEC_SILENCE,
+        .min_split_time = IRDA_NEC_MIN_SPLIT_TIME,
     },
-    .databit_len = 32,
+    .databit_len[0] = 42,
+    .databit_len[1] = 32,
     .no_stop_bit = false,
-    .decode = irda_common_decode_pdm,
+    .decode = irda_common_decode_pdwm,
     .encode = irda_common_encode_pdwm,
     .interpret = irda_decoder_nec_interpret,
     .decode_repeat = irda_decoder_nec_decode_repeat,
@@ -34,9 +36,9 @@ const IrdaCommonProtocolSpec protocol_samsung32 = {
         .bit_tolerance = IRDA_SAMSUNG_BIT_TOLERANCE,
         .silence_time = IRDA_SAMSUNG_SILENCE,
     },
-    .databit_len = 32,
+    .databit_len[0] = 32,
     .no_stop_bit = false,
-    .decode = irda_common_decode_pdm,
+    .decode = irda_common_decode_pdwm,
     .encode = irda_common_encode_pdwm,
     .interpret = irda_decoder_samsung32_interpret,
     .decode_repeat = irda_decoder_samsung32_decode_repeat,
@@ -52,7 +54,7 @@ const IrdaCommonProtocolSpec protocol_rc6 = {
         .bit_tolerance = IRDA_RC6_BIT_TOLERANCE,
         .silence_time = IRDA_RC6_SILENCE,
     },
-    .databit_len = 1 + 3 + 1 + 8 + 8,   // start_bit + 3 mode bits, + 1 toggle bit (x2 timing) + 8 address + 8 command
+    .databit_len[0] = 1 + 3 + 1 + 8 + 8,   // start_bit + 3 mode bits, + 1 toggle bit (x2 timing) + 8 address + 8 command
     .manchester_start_from_space = false,
     .decode = irda_decoder_rc6_decode_manchester,
     .encode = irda_encoder_rc6_encode_manchester,
@@ -70,7 +72,7 @@ const IrdaCommonProtocolSpec protocol_rc5 = {
         .bit_tolerance = IRDA_RC5_BIT_TOLERANCE,
         .silence_time = IRDA_RC5_SILENCE,
     },
-    .databit_len = 1 + 1 + 1 + 5 + 6,   // start_bit + start_bit/command_bit + toggle_bit + 5 address + 6 command
+    .databit_len[0] = 1 + 1 + 1 + 5 + 6,   // start_bit + start_bit/command_bit + toggle_bit + 5 address + 6 command
     .manchester_start_from_space = true,
     .decode = irda_common_decode_manchester,
     .encode = irda_common_encode_manchester,
@@ -90,10 +92,13 @@ const IrdaCommonProtocolSpec protocol_sirc = {
         .preamble_tolerance = IRDA_SIRC_PREAMBLE_TOLERANCE,
         .bit_tolerance = IRDA_SIRC_BIT_TOLERANCE,
         .silence_time = IRDA_SIRC_SILENCE,
+        .min_split_time = IRDA_SIRC_MIN_SPLIT_TIME,
     },
-    .databit_len = 20,  /* 12/15/20 */
+    .databit_len[0] = 20,
+    .databit_len[1] = 15,
+    .databit_len[2] = 12,
     .no_stop_bit = true,
-    .decode = irda_common_decode_pwm,
+    .decode = irda_common_decode_pdwm,
     .encode = irda_common_encode_pdwm,
     .interpret = irda_decoder_sirc_interpret,
     .decode_repeat = NULL,

+ 1 - 0
lib/irda/encoder_decoder/irda.c

@@ -45,6 +45,7 @@ static const IrdaEncoderDecoder irda_encoder_decoder[] = {
           .alloc = irda_decoder_nec_alloc,
           .decode = irda_decoder_nec_decode,
           .reset = irda_decoder_nec_reset,
+          .check_ready = irda_decoder_nec_check_ready,
           .free = irda_decoder_nec_free},
       .encoder = {
           .alloc = irda_encoder_nec_alloc,

+ 10 - 8
lib/irda/encoder_decoder/irda.h

@@ -21,14 +21,16 @@ typedef struct IrdaEncoderHandler IrdaEncoderHandler;
 typedef enum {
     IrdaProtocolUnknown = -1,
     IrdaProtocolNEC = 0,
-    IrdaProtocolNECext = 1,
-    IrdaProtocolSamsung32 = 2,
-    IrdaProtocolRC6 = 3,
-    IrdaProtocolRC5 = 4,
-    IrdaProtocolRC5X = 5,
-    IrdaProtocolSIRC = 6,
-    IrdaProtocolSIRC15 = 7,
-    IrdaProtocolSIRC20 = 8,
+    IrdaProtocolNECext,
+    IrdaProtocolNEC42,
+    IrdaProtocolNEC42ext,
+    IrdaProtocolSamsung32,
+    IrdaProtocolRC6,
+    IrdaProtocolRC5,
+    IrdaProtocolRC5X,
+    IrdaProtocolSIRC,
+    IrdaProtocolSIRC15,
+    IrdaProtocolSIRC20,
     IrdaProtocolMAX,
 } IrdaProtocol;
 

+ 1 - 0
lib/irda/encoder_decoder/irda_i.h

@@ -4,6 +4,7 @@
 #include <stdint.h>
 
 typedef struct {
+    uint32_t min_split_time;
     uint32_t silence_time;
     uint16_t preamble_mark;
     uint16_t preamble_space;

+ 6 - 4
lib/irda/encoder_decoder/irda_protocol_defs_i.h

@@ -23,12 +23,13 @@
 #define IRDA_NEC_PREAMBLE_MARK          9000
 #define IRDA_NEC_PREAMBLE_SPACE         4500
 #define IRDA_NEC_BIT1_MARK              560
-#define IRDA_NEC_BIT1_SPACE             1600
+#define IRDA_NEC_BIT1_SPACE             1690
 #define IRDA_NEC_BIT0_MARK              560
 #define IRDA_NEC_BIT0_SPACE             560
 #define IRDA_NEC_REPEAT_PERIOD          110000
 #define IRDA_NEC_SILENCE                IRDA_NEC_REPEAT_PERIOD
-#define IRDA_NEC_REPEAT_PAUSE_MIN       30000
+#define IRDA_NEC_MIN_SPLIT_TIME         IRDA_NEC_REPEAT_PAUSE_MIN
+#define IRDA_NEC_REPEAT_PAUSE_MIN       4000
 #define IRDA_NEC_REPEAT_PAUSE_MAX       150000
 #define IRDA_NEC_REPEAT_MARK            9000
 #define IRDA_NEC_REPEAT_SPACE           2250
@@ -38,6 +39,7 @@
 void* irda_decoder_nec_alloc(void);
 void irda_decoder_nec_reset(void* decoder);
 void irda_decoder_nec_free(void* decoder);
+IrdaMessage* irda_decoder_nec_check_ready(void* decoder);
 IrdaMessage* irda_decoder_nec_decode(void* decoder, bool level, uint32_t duration);
 void* irda_encoder_nec_alloc(void);
 IrdaStatus irda_encoder_nec_encode(void* encoder_ptr, uint32_t* duration, bool* level);
@@ -143,7 +145,7 @@ void irda_encoder_rc6_reset(void* encoder_ptr, const IrdaMessage* message);
 void irda_encoder_rc6_free(void* decoder);
 IrdaStatus irda_encoder_rc6_encode(void* encoder_ptr, uint32_t* duration, bool* polarity);
 bool irda_decoder_rc6_interpret(IrdaCommonDecoder* decoder);
-IrdaStatus irda_decoder_rc6_decode_manchester(IrdaCommonDecoder* decoder);
+IrdaStatus irda_decoder_rc6_decode_manchester(IrdaCommonDecoder* decoder, bool level, uint32_t timing);
 IrdaStatus irda_encoder_rc6_encode_manchester(IrdaCommonEncoder* encoder_ptr, uint32_t* duration, bool* polarity);
 const IrdaProtocolSpecification* irda_rc6_get_spec(IrdaProtocol protocol);
 
@@ -229,7 +231,7 @@ extern const IrdaCommonProtocolSpec protocol_rc5;
 #define IRDA_SIRC_PREAMBLE_TOLERANCE           200     // us
 #define IRDA_SIRC_BIT_TOLERANCE                120     // us
 #define IRDA_SIRC_SILENCE                      10000
-#define IRDA_SIRC_MIN_SILENCE                  (IRDA_SIRC_SILENCE - 1000)
+#define IRDA_SIRC_MIN_SPLIT_TIME               (IRDA_SIRC_SILENCE - 1000)
 #define IRDA_SIRC_REPEAT_PERIOD                45000
 
 

+ 39 - 9
lib/irda/encoder_decoder/nec/irda_decoder_nec.c

@@ -1,3 +1,4 @@
+#include "common/irda_common_i.h"
 #include "irda.h"
 #include "irda_protocol_defs_i.h"
 #include <stdbool.h>
@@ -6,26 +7,55 @@
 #include "../irda_i.h"
 
 
+IrdaMessage* irda_decoder_nec_check_ready(void* ctx) {
+    return irda_common_decoder_check_ready(ctx);
+}
+
 bool irda_decoder_nec_interpret(IrdaCommonDecoder* decoder) {
     furi_assert(decoder);
 
     bool result = false;
-    uint8_t address = decoder->data[0];
-    uint8_t address_inverse = decoder->data[1];
-    uint8_t command = decoder->data[2];
-    uint8_t command_inverse = decoder->data[3];
 
-    if (command == (uint8_t) ~command_inverse) {
-        if (address == (uint8_t) ~address_inverse) {
+    if (decoder->databit_cnt == 32) {
+        uint8_t address = decoder->data[0];
+        uint8_t address_inverse = decoder->data[1];
+        uint8_t command = decoder->data[2];
+        uint8_t command_inverse = decoder->data[3];
+        if ((command == (uint8_t) ~command_inverse) && (address == (uint8_t) ~address_inverse)) {
             decoder->message.protocol = IrdaProtocolNEC;
             decoder->message.address = address;
+            decoder->message.command = command;
+            decoder->message.repeat = false;
+            result = true;
         } else {
             decoder->message.protocol = IrdaProtocolNECext;
             decoder->message.address = decoder->data[0] | (decoder->data[1] << 8);
+            decoder->message.command = decoder->data[2] | (decoder->data[3] << 8);
+            decoder->message.repeat = false;
+            result = true;
+        }
+    } else if (decoder->databit_cnt == 42) {
+        uint32_t* data1 = (void*) decoder->data;
+        uint16_t* data2 = (void*) (data1 + 1);
+        uint16_t address = *data1 & 0x1FFF;
+        uint16_t address_inverse = (*data1 >> 13) & 0x1FFF;
+        uint16_t command = ((*data1 >> 26) & 0x3F) | ((*data2 & 0x3) << 6);
+        uint16_t command_inverse = (*data2 >> 2) & 0xFF;
+
+        if ((address == (~address_inverse & 0x1FFF))
+            && (command == (~command_inverse & 0xFF))) {
+            decoder->message.protocol = IrdaProtocolNEC42;
+            decoder->message.address = address;
+            decoder->message.command = command;
+            decoder->message.repeat = false;
+            result = true;
+        } else {
+            decoder->message.protocol = IrdaProtocolNEC42ext;
+            decoder->message.address = address | (address_inverse << 13);
+            decoder->message.command = command | (command_inverse << 8);
+            decoder->message.repeat = false;
+            result = true;
         }
-        decoder->message.command = command;
-        decoder->message.repeat = false;
-        result = true;
     }
 
     return result;

+ 30 - 11
lib/irda/encoder_decoder/nec/irda_encoder_nec.c

@@ -20,26 +20,45 @@ void irda_encoder_nec_reset(void* encoder_ptr, const IrdaMessage* message) {
     IrdaCommonEncoder* encoder = encoder_ptr;
     irda_common_encoder_reset(encoder);
 
-    uint8_t address = message->address;
-    uint8_t address_inverse = ~address;
-    uint8_t command = message->command;
-    uint8_t command_inverse = ~command;
-
-    uint32_t* data = (void*) encoder->data;
+    uint32_t* data1 = (void*) encoder->data;
+    uint32_t* data2 = data1 + 1;
     if (message->protocol == IrdaProtocolNEC) {
-        *data = (address | (address_inverse << 8));
+        uint8_t address = message->address;
+        uint8_t address_inverse = ~address;
+        uint8_t command = message->command;
+        uint8_t command_inverse = ~command;
+        *data1 = address;
+        *data1 |= address_inverse << 8;
+        *data1 |= command << 16;
+        *data1 |= command_inverse << 24;
+        encoder->bits_to_encode = 32;
     } else if (message->protocol == IrdaProtocolNECext) {
-        *data = (uint16_t) message->address;
+        *data1 = (uint16_t) message->address;
+        *data1 |= (message->command & 0xFFFF) << 16;
+        encoder->bits_to_encode = 32;
+    } else if (message->protocol == IrdaProtocolNEC42) {
+        /* 13 address + 13 inverse address + 8 command + 8 inv command */
+        *data1 = message->address & 0x1FFFUL;
+        *data1 |= (~message->address & 0x1FFFUL) << 13;
+        *data1 |= ((message->command & 0x3FUL) << 26);
+        *data2 = (message->command & 0xC0UL) >> 6;
+        *data2 |= (~message->command & 0xFFUL) << 2;
+        encoder->bits_to_encode = 42;
+    } else if (message->protocol == IrdaProtocolNEC42ext) {
+        *data1 = message->address & 0x3FFFFFF;
+        *data1 |= ((message->command & 0x3F) << 26);
+        *data2 = (message->command & 0xFFC0) >> 6;
+        encoder->bits_to_encode = 42;
+    } else {
+        furi_assert(0);
     }
-    *data |= command << 16;
-    *data |= command_inverse << 24;
 }
 
 IrdaStatus irda_encoder_nec_encode_repeat(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level) {
     furi_assert(encoder);
 
     /* space + 2 timings preambule + payload + stop bit */
-    uint32_t timings_encoded_up_to_repeat = 1 + 2 + encoder->protocol->databit_len * 2 + 1;
+    uint32_t timings_encoded_up_to_repeat = 1 + 2 + encoder->bits_to_encode * 2 + 1;
     uint32_t repeat_cnt = encoder->timings_encoded - timings_encoded_up_to_repeat;
 
     furi_assert(encoder->timings_encoded >= timings_encoded_up_to_repeat);

+ 20 - 0
lib/irda/encoder_decoder/nec/irda_nec_spec.c

@@ -12,16 +12,36 @@ static const IrdaProtocolSpecification irda_nec_protocol_specification = {
 static const IrdaProtocolSpecification irda_necext_protocol_specification = {
       .name = "NECext",
       .address_length = 16,
+      .command_length = 16,
+      .frequency = IRDA_COMMON_CARRIER_FREQUENCY,
+      .duty_cycle = IRDA_COMMON_DUTY_CYCLE,
+};
+
+static const IrdaProtocolSpecification irda_nec42_protocol_specification = {
+      .name = "NEC42",
+      .address_length = 13,
       .command_length = 8,
       .frequency = IRDA_COMMON_CARRIER_FREQUENCY,
       .duty_cycle = IRDA_COMMON_DUTY_CYCLE,
 };
 
+static const IrdaProtocolSpecification irda_nec42ext_protocol_specification = {
+      .name = "NEC42ext",
+      .address_length = 26,
+      .command_length = 16,
+      .frequency = IRDA_COMMON_CARRIER_FREQUENCY,
+      .duty_cycle = IRDA_COMMON_DUTY_CYCLE,
+};
+
 const IrdaProtocolSpecification* irda_nec_get_spec(IrdaProtocol protocol) {
     if (protocol == IrdaProtocolNEC)
         return &irda_nec_protocol_specification;
     else if (protocol == IrdaProtocolNECext)
         return &irda_necext_protocol_specification;
+    else if (protocol == IrdaProtocolNEC42)
+        return &irda_nec42_protocol_specification;
+    else if (protocol == IrdaProtocolNEC42ext)
+        return &irda_nec42ext_protocol_specification;
     else
         return NULL;
 }

+ 1 - 0
lib/irda/encoder_decoder/rc5/irda_encoder_rc5.c

@@ -30,6 +30,7 @@ void irda_encoder_rc5_reset(void* encoder_ptr, const IrdaMessage* message) {
     common_encoder->data[0] = ~common_encoder->data[0];
     common_encoder->data[1] = ~common_encoder->data[1];
 
+    common_encoder->bits_to_encode = common_encoder->protocol->databit_len[0];
     encoder->toggle_bit ^= 1;
 }
 

+ 5 - 9
lib/irda/encoder_decoder/rc6/irda_decoder_rc6.c

@@ -50,39 +50,35 @@ bool irda_decoder_rc6_interpret(IrdaCommonDecoder* decoder) {
  * it separately and than pass decoding for other bits to
  * common manchester decode function.
  */
-IrdaStatus irda_decoder_rc6_decode_manchester(IrdaCommonDecoder* decoder) {
+IrdaStatus irda_decoder_rc6_decode_manchester(IrdaCommonDecoder* decoder, bool level, uint32_t timing) {
     // 4th bit lasts 2x times more
     IrdaStatus status = IrdaStatusError;
     uint16_t bit = decoder->protocol->timings.bit1_mark;
     uint16_t tolerance = decoder->protocol->timings.bit_tolerance;
-    uint16_t timing = decoder->timings[0];
 
     bool single_timing = MATCH_TIMING(timing, bit, tolerance);
     bool double_timing = MATCH_TIMING(timing, 2*bit, tolerance);
     bool triple_timing = MATCH_TIMING(timing, 3*bit, tolerance);
 
     if (decoder->databit_cnt == 4) {
-        furi_assert(decoder->timings_cnt == 1);
         furi_assert(decoder->switch_detect == true);
 
         if (single_timing ^ triple_timing) {
-            --decoder->timings_cnt;
             ++decoder->databit_cnt;
-            decoder->data[0] |= (single_timing ? !decoder->level : decoder->level) << 4;
+            decoder->data[0] |= (single_timing ? !level : level) << 4;
             status = IrdaStatusOk;
         }
     } else if (decoder->databit_cnt == 5) {
         if (single_timing || triple_timing) {
             if (triple_timing)
-                decoder->timings[0] = bit;
+                timing = bit;
             decoder->switch_detect = false;
-            status = irda_common_decode_manchester(decoder);
+            status = irda_common_decode_manchester(decoder, level, timing);
         } else if (double_timing) {
-            --decoder->timings_cnt;
             status = IrdaStatusOk;
         }
     } else {
-        status = irda_common_decode_manchester(decoder);
+        status = irda_common_decode_manchester(decoder, level, timing);
     }
 
     return status;

+ 1 - 0
lib/irda/encoder_decoder/rc6/irda_encoder_rc6.c

@@ -24,6 +24,7 @@ void irda_encoder_rc6_reset(void* encoder_ptr, const IrdaMessage* message) {
     *data |= reverse(message->address) << 5;
     *data |= reverse(message->command) << 13;
 
+    common_encoder->bits_to_encode = common_encoder->protocol->databit_len[0];
     encoder->toggle_bit ^= 1;
 }
 

+ 3 - 1
lib/irda/encoder_decoder/samsung/irda_encoder_samsung.c

@@ -29,13 +29,15 @@ void irda_encoder_samsung32_reset(void* encoder_ptr, const IrdaMessage* message)
     *data |= address << 8;
     *data |= command << 16;
     *data |= command_inverse << 24;
+
+    encoder->bits_to_encode = encoder->protocol->databit_len[0];
 }
 
 IrdaStatus irda_encoder_samsung32_encode_repeat(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level) {
     furi_assert(encoder);
 
     /* space + 2 timings preambule + payload + stop bit */
-    uint32_t timings_encoded_up_to_repeat = 1 + 2 + encoder->protocol->databit_len * 2 + 1;
+    uint32_t timings_encoded_up_to_repeat = 1 + 2 + encoder->bits_encoded * 2 + 1;
     uint32_t repeat_cnt = encoder->timings_encoded - timings_encoded_up_to_repeat;
 
     furi_assert(encoder->timings_encoded >= timings_encoded_up_to_repeat);

+ 3 - 33
lib/irda/encoder_decoder/sirc/irda_decoder_sirc.c

@@ -8,16 +8,7 @@
 
 
 IrdaMessage* irda_decoder_sirc_check_ready(void* ctx) {
-    IrdaMessage* message = NULL;
-    IrdaCommonDecoder* decoder = ctx;
-
-    if (irda_decoder_sirc_interpret(decoder)) {
-        message = &decoder->message;
-        decoder->timings_cnt = 0;
-        decoder->databit_cnt = 0;
-    }
-
-    return message;
+    return irda_common_decoder_check_ready(ctx);
 }
 
 bool irda_decoder_sirc_interpret(IrdaCommonDecoder* decoder) {
@@ -57,29 +48,8 @@ void* irda_decoder_sirc_alloc(void) {
     return irda_common_decoder_alloc(&protocol_sirc);
 }
 
-IrdaMessage* irda_decoder_sirc_decode(void* context, bool level, uint32_t duration) {
-    IrdaCommonDecoder* decoder = context;
-    IrdaMessage* message = NULL;
-
-    if ((decoder->databit_cnt == 12) || (decoder->databit_cnt == 15)) {
-        if (!level && (duration >= IRDA_SIRC_MIN_SILENCE)) {
-            if (irda_decoder_sirc_interpret(decoder)) {
-                message = &decoder->message;
-                decoder->timings_cnt = 0;
-                decoder->databit_cnt = 0;
-            }
-        }
-    }
-
-    if (!message) {
-        message = irda_common_decode(decoder, level, duration);
-        if (message) {  /* 20 bit */
-            decoder->timings_cnt = 0;
-            decoder->databit_cnt = 0;
-        }
-    }
-
-    return message;
+IrdaMessage* irda_decoder_sirc_decode(void* decoder, bool level, uint32_t duration) {
+    return irda_common_decode(decoder, level, duration);
 }
 
 void irda_decoder_sirc_free(void* decoder) {

+ 10 - 26
lib/irda/encoder_decoder/sirc/irda_encoder_sirc.c

@@ -7,34 +7,27 @@
 #include <furi.h>
 
 
-typedef struct {
-    IrdaCommonEncoder* common_encoder;
-    uint8_t databits;
-} IrdaSircEncoder;
-
-
 void irda_encoder_sirc_reset(void* encoder_ptr, const IrdaMessage* message) {
     furi_assert(encoder_ptr);
     furi_assert(message);
 
     IrdaCommonEncoder* encoder = encoder_ptr;
-    IrdaSircEncoder* encoder_sirc = encoder->context;
     irda_common_encoder_reset(encoder);
 
     uint32_t* data = (void*) encoder->data;
 
     if (message->protocol == IrdaProtocolSIRC) {
-        encoder_sirc->databits = 12;
         *data = (message->command & 0x7F);
         *data |= (message->address & 0x1F) << 7;
+        encoder->bits_to_encode = 12;
     } else if (message->protocol == IrdaProtocolSIRC15) {
-        encoder_sirc->databits = 15;
         *data = (message->command & 0x7F);
         *data |= (message->address & 0xFF) << 7;
+        encoder->bits_to_encode = 15;
     } else if (message->protocol == IrdaProtocolSIRC20) {
-        encoder_sirc->databits = 20;
         *data = (message->command & 0x7F);
         *data |= (message->address & 0x1FFF) << 7;
+        encoder->bits_to_encode = 20;
     } else {
         furi_assert(0);
     }
@@ -43,9 +36,7 @@ void irda_encoder_sirc_reset(void* encoder_ptr, const IrdaMessage* message) {
 IrdaStatus irda_encoder_sirc_encode_repeat(IrdaCommonEncoder* encoder, uint32_t* duration, bool* level) {
     furi_assert(encoder);
 
-    IrdaSircEncoder* encoder_sirc = encoder->context;
-
-    uint32_t timings_in_message = 1 + 2 + encoder_sirc->databits * 2;
+    uint32_t timings_in_message = 1 + 2 + encoder->bits_to_encode * 2 - 1;
     furi_assert(encoder->timings_encoded == timings_in_message);
 
     furi_assert(encoder->timings_sum < IRDA_SIRC_REPEAT_PERIOD);
@@ -61,28 +52,21 @@ IrdaStatus irda_encoder_sirc_encode_repeat(IrdaCommonEncoder* encoder, uint32_t*
 }
 
 void* irda_encoder_sirc_alloc(void) {
-    IrdaCommonEncoder* encoder_common = irda_common_encoder_alloc(&protocol_sirc);
-    IrdaSircEncoder* encoder_sirc = furi_alloc(sizeof(IrdaSircEncoder));
-    encoder_sirc->common_encoder = encoder_common;
-    encoder_common->context = encoder_sirc;
-    return encoder_common;
+    return irda_common_encoder_alloc(&protocol_sirc);
 }
 
 void irda_encoder_sirc_free(void* encoder_ptr) {
-    IrdaCommonEncoder* encoder = encoder_ptr;
-    free(encoder->context);
-    irda_common_encoder_free(encoder);
+    irda_common_encoder_free(encoder_ptr);
 }
 
 IrdaStatus irda_encoder_sirc_encode(void* encoder_ptr, uint32_t* duration, bool* level) {
-    IrdaCommonEncoder* encoder_common = encoder_ptr;
-    IrdaSircEncoder* encoder_sirc = encoder_common->context;
+    IrdaCommonEncoder* encoder = encoder_ptr;
 
-    IrdaStatus status = irda_common_encode(encoder_ptr, duration, level);
-    if ((status == IrdaStatusOk) && (encoder_common->bits_encoded == encoder_sirc->databits)) {
+    IrdaStatus status = irda_common_encode(encoder, duration, level);
+    if ((status == IrdaStatusOk) && (encoder->bits_encoded == encoder->bits_to_encode)) {
         furi_assert(!*level);
         status = IrdaStatusDone;
-        encoder_common->state = IrdaCommonEncoderStateEncodeRepeat;
+        encoder->state = IrdaCommonEncoderStateEncodeRepeat;
     }
     return status;
 }