IRMP-org / IRMP

Infrared Multi Protocol Decoder
GNU General Public License v3.0
273 stars 44 forks source link

May be useful for ya. #8

Closed kdschlosser closed 3 years ago

kdschlosser commented 4 years ago

I wrote a python decoder/encoder that supports over 150 protocols. It might be helpful to you with this project. Python is a really easy language to read and understand what is going on it is also fairly simple to port to C.

The best part about this library is it's use of a common class to decode the majority of the protocols. If memory serves there are about 4 or 5 protocols are not handled by this common decoder. I can pretty easily add support to this class for "multi bit" timings but seeing as how there are a small number of them I didn't see the need to.

I figured it would help out quite a bit in adding new protocols to your library. I am still working on it and fine tuning things. I will also be adding in support for air conditioners as well.

Have a look see and if there are any questions I am able to answer I would be more then willing to help out if I am able to. https://github.com/kdschlosser/pyIRDecoder

There are a couple of protocols that you have in this library that I would be interested in adding to my library if that would be OK with you. I will probably have a few questions if it is OK that I add them.

ArminJo commented 4 years ago

Thanks a lot for your offer! Do you have any tutorial / pictures / schematics about the connections and any info about the hosts? Can it run on plain Arduinos? How much RAM do you need? Maybe I can place a link to your program. IRMP protocols are described here.

kdschlosser commented 4 years ago

My library is written in Python. so no Arduinos. It would run on an ESP32 that has been flashed with MicroPython.

The library is also standalone, meaning it is not keyed to any specific type of receiver or transmitter. So a person could really easily use an Arduino to capture the RLC of an incoming IR signal and send it over to some other device that is capable of running Python.

Python is a fairly simple language to read, I thought it might be helpful to ya to use as a reference for the protocols or if you wanted to see how I went about setting up the decoder.

Arduinos are where I first started programming. I know how hard it is to write complex code on them... I can tell you that it takes on average 2 milliseconds (running on a PC) for a code to get decoded. the RLC that is passed has to go down each of the protocols until it finds a match. with 150 protocols 2 milliseconds is pretty quick. If I compiled the thing as C code it would be somewhere between 50 and 200 times faster.

Since you are more up to snuff then I with the Arduinos I cam up with an idea that would allow you to decode any protocol that currently exists. And you would be able to do it in a fraction of the ram you are currently using. That is if my idea is sound.

The biggest problem that you face on the arduinos is RAM. because IR codes can be large in length you need to declare an array that has the size capable of holding the longest set of timings for the protocols your library supports. and this array has to be an int32 array. so that can get really costly on the small amount of RAM an Arduino has.

This is what I propose. What if instead of holding the individual timings you have an array that holds one of each of the different timings in the entire RLC. You would have to do some kind of a check with a tolerance to see if a mark or a space matches what is already in that array. The index numbers for each of the unique timings is the index that would be used to get the locations of those timings from another array. That second array has the exact same length as the first array and in each one of the locations is a bitfield. a set pit at a specific position means that a timing is in that position.

here is an example. say the IR code being received is

[
+1778, 0
-889,    1
+889,   2
-1778,  3
+1778,  4
-1778  5
,+889,  6
-889,  7
+6889,  8
-889  9
,+889,  10
-889,  11
+889,  12
-889,  13
+889,  14
-889,  15
+1778,  16
-889,  17
+889,  18
-889,  19
+889,  20
-90886  21
]

after the code has been received and everything is sorted where it needs to go. This is what you would end up with

in the timings array you would have

{
    +1778,
    -889,
    +889,
    -1778,
    +6889,
    -90866
}

in the positions array you would have

{
    0b0000010000000000010001,
    0b0010101010101010000010,
    0b0101000101010001000100,
    0b0000000000000000101000,
    0b0000000000000100000000,
    0b1000000000000000000000 
}

so instead of having to have an array that has 22 positions and takes up 4 bytes each position totaling 88 bytes. Now you can have 2 arrays that have 6 positions in each array for a total of 12 positions taking 4 bytes each for a total of 48 bytes.

I know that this is a hypothetical and you would have to allocate each array so it would be large enough to hold the most complex protocol. So lets cive this a shot with the Fujitsu128 protocol which is a behemoth of a protocol this would require an int32 array that is (128 * 2) + 4 in size. which would take up 1040 bytes of memory. Probably not going to happen on an UNO.

There are only 6 different timing values in this protocol. mark = 413, -413 space = 413, -1239 lean_in = 3304, 1652 lead_out = 413, -???

This same code (which is the longest code I believe outside of air conditioners) that would need an int32 array that has a length of 260 now needs an int32 array that has a length of 6 and an int32 array that has a length 54

the length of 54 would be 9 int32's for each timing. we need to represent 260 marks and spaces.

for first array would take up 24 bytes of RAM and the second would take up 216 bytes. for a total of 240 bytes. This consumes 75% less memory!!!! That's one hell of a compression!!! This would be the largest the bitfield array would ever need to be. Next protocol down in size I think is < 70 bits I would have to check.

The only thing I am not sure of is if you would be able to do an iteration over the timings array to see if you can find a match for a timing that may or may not already exist during the interrupt.

ArminJo commented 4 years ago

Thanks! BTW do you know IrScrutinizer

kdschlosser commented 4 years ago

I do. I looked t using it to decode IR. The problem is it takes 2-3 seconds for it to decode RLC. 2-3 seconds cannot be used in real time applications.

I am one of the authors and the administrator for a program called EventGhost. you may or may not have heard of it. It is one of the "elders" in the world of home automation. it has been around about 14 years now. EventGhost is known for it's abilities to interface with the Windows ehome drivers specifically the IR portions of it.

This interface has been problematic over the years and made use of a service called alternatemceir. This service had issues in it's self. I decided that is was time to give the IR portion of EventGhost a facelift. It currently can decode 10 protocols and it has 0 encoding capabilities. after I am done with this update the service is no longer going to be needed. I wrote a pure python interface to the ehome drivers for handle the IR that doesn't have the issues that the service had. and it will support 152 protocols encoding and decoding with the ability to connect to a database that I am going to host on our server so a friendly name can be tied to a code and this is what will be displayed to the user instead of a bunch of numbers that are meaningless to the users. The database has over 100k codes already stored in it and a user will be able to search that database for transmitting and also submit codes that have not already been added.

I have included in my library user friendly translations of the codes for protocols like MCE, XBox One, XBox 360, Sony 8, Sony 12, Sony 15 Sony 20, Sky (remote and keyboard), Sky HD (remote and keyboard), Sky Plus (remote and keyboard) as well as a few others.

I made this library so it is not attached to any kind of a transceiver for a purpose It can now be included into a project for anyone wanting to write the code to interface with any kind of a transceiver. There is not one decoder available for Python. and most of the ones written in C are attached to some kind of a transceiver, whether it be an Arduino or an ESP some kind of an attachment exists. if a decoder existed that could be compiled as a shared library I could have used this and it would be fast. Anything that is written in Java cannot be used because it is to slow and if it is designed to stay running and accept multiple decode queries it is to much of a resource hog because of the JVM. Java also has poor garbage collecting routines and doesn't release resources back to the OS properly.

One of the things you also might want to have a look at is the "universal" protocol and also the smoothing of the RLC that gets done by this protocol. the universal protocol is there for IR codes that the library may not support. the smoothing is there so identical codes get spit out for the same button being pressed more then once. Because there are variations in a received code even from the same button being pressed a universal approach has not really been done with accuracy. Not until now. the smoothing I do on the RLC to be decoded looks at the whole code and obtains the average of like marks and spaces, it then applies this averaged timing to the timings that were included in the average once it is done with that then it rounds the timings to the nearest 50us. I just updated the Universal decoder to handle biphase (manchester encoding) IR codes properly so it will expand the pulses into their proper bit representations. I also have it weed out any "middle timings" that are only used as separators.

It's not perfect but it is far better then raising an exception of some kind or returning nothing at all. At least this way there might be something available the user is able to use.