Help me understand what I'm missing on IR encoding/decoding.

I read in a tagline on here that the key to getting good answers lies in asking good questions, so I’ll do my best to give all the relevant information. I’m looking for a way to communicate team and player information over infrared for a game for a camp I run.

I’m early enough in the project that I don’t really have much preference for how this data is formatted, but I would like there to be some sort of order to it. I would eventually like to build this ir message by concatenating some variables because I don’t want it to be static. In other words, if certain things happen, you might change from team 1 to team 2. That sort of thing.

Ok, so even though I don’t have any preference for data type, I’m thinking shorter and simpler would be easier. I’ve been able to transmit my signal 200+ yards with only the arduino’s 5v out, a 2n2222a, and a cheap lens. I’m super happy with that part. It’s the data that I’m having issues with.

My original thought was that I would go with team being the first digit 1-9 (hex throws out leading 0’s) and then a 3 digit player number. So 1001 would signify team 1, player 0001. 5132 would be team 5, player 132. I hope that makes sense.

So, I’ve made a sketch that shoots out 5 of these preformatted IR Blasts as such

   irsend.sendSony(0x3E8, 12);//Team 1, Player 000 (1000)
    delay(150);
    irsend.sendSony(0x7CF, 12);//Team 1, Player 999 (1999)
    delay(150);
    irsend.sendSony(0x2328, 12);//Team 9, Player 000 (9000)
    delay(150);
    irsend.sendSony(0x270F, 12);//Team 9, Player 999 (9999)
    delay(150);
    irsend.sendSony(0x140C, 12);//Team 5, Player 132 (5132)
    delay(150);

The de-defacto IR Receive Dump Sketch (basically this one)

Receives the first two fine.
irsend.sendSony(0x3E8, 12); is received as 3E8 (1000)
irsend.sendSony(0x7CF, 12); is received as 7CF (1999)
irsend.sendSony(0x2328, 12); BUT is received as 328 (808)
irsend.sendSony(0x270F, 12); AND is received as 70F (1807)
irsend.sendSony(0x140C, 12); AND is received as 40C (1036)

I’m pretty sure this is due to the bit length. I was kind of hoping 12 would be enough to cover that 4 digit number but that’s obviously not the case. Extending the bit length on those last 3 causes them to work and breaks the first 2.

So…finally…what I’m asking for is there any format where I can either have a fixed bit length or be able to calculate this bit length on the fly so I can have some semblance of order to my code. I feel like this has to be doable, I just don’t know enough of the ins and outs of c and IR to format it properly. So far it has been trial and error.

Thanks for your time!

I’m making a little progress. It seems to me that I have to keep my data within what the arduino (or more specifically, the IR library) perceives as being in a certain address space size or whatever you would call it.

If the number So if a number is input that is 16 bit and it’s below 1024, it is interpreted as 8 bit. I get that. Not all IR types seem to speak all bit lengths. It seems to me like a 16 bit address space is ideal.

I can start the number with a 2 (to prevent it from being too low or above 32768).
I can use the next 4 digits to be my team/player and I’ll never cross over into the next bit size. (so it seems).

So question 1…am I over thinking this? I’ve spent a ridiculous amount of time on trial and error to get a data set that will work for what seems like a simple task.

Question 2…the first working solution I came up with was to use 16 bit JVC with the lead in bit (hence the 0 after the 16). The JVC doesn’t seem quite as reliable as the irsend.sendSony. It fairly regularly misinterprets a signal as being 32 bits, although shooting it multiple times will eventually get you the right decoding.

The arduino can properly decode this code below about 75% of the time with the top 2 being almost 100% of the time. Is there a better way?

   irsend.sendJVC(0x4E85, 16,0);//Team 01, Player 01 (20101)
    delay(250);
    irsend.sendJVC(0x752F, 16,0);//Team 99, Player 99 (29999)
    delay(250);
    irsend.sendJVC(0x5034, 16,0);//20532
    delay(250);
    irsend.sendJVC(0x54DB, 16,0);//21723 
    delay(250);
    irsend.sendJVC(0x4EE7, 16,0);//20199
    delay(250);
    irsend.sendJVC(0x5228, 16,0);//21032
    delay(250);

You’re quite right about that tagline :slight_smile:

First a counter question: why IR rather than 433 MHz wireless? Advantages are that the second is meant for this distance (IR is mostly used for short distance) and it doesn’t need line of sight (IR does - have smoke, mist or a tree in the way and you lose connection).

 irsend.sendSony(0x2328, 12);

That number 12, is that the number of bits sent out? It seems so, as what you receive is a 12-bit value. If so, increase that to 16 to send out all the 16 bits in that number.

You can anyway pack your numbers better. Your player numbers appear to go to 999, that fits in 10 bits (0-1023). Team numbers to 9, that’s 4 bits (0-15). So you need just 14 bits for that - make that two bytes. If you have no more than 8 teams and 512 players you can bring it down to 12 bits: 3 for the team number and 9 for the player number.

uint16_t team = 6;
uint16_t player = 332;

// Pack these two in a single value: bit 13-10 for team, bit 9-0 for player.
uint16_t code = team << 10 | player;

// Unpack code to team and player:
team = code >> 10;
player = code & 0x03FF;

There you go. 16 bits down to 14.

if a number is input that is 16 bit and it's below 1024, it is interpreted as 8 bit.

1023 is a ten bit number - it cannot be represented in a single byte of only eight bits.

AWOL:
1023 is a ten bit number - it cannot be represented in a single byte of only eight bits.

That's why I said interpreted. I meant that the receiver THINKS it is 16 bits. Sorry for explaining that wrong.

Why not 433mhz...
It's because it's more akin to a laser-tag type game. The signals need to be directed at a particular target.

Your code is really interesting. I'd like to explore that more. The issue I'm dealing with is the libraries themselves. They're expecting certain formatting. It's not like I can just send it the minimal amount of bits necessary. If I send it as Sony, it's expecting 12 bits, no more, no less, otherwise I don't get the expected results on the other end.

PLEASE tell me if there's something I'm not understanding, but from what I can tell the IR send/receive needs the table of possible data sent through it to absolutely be a fixed bit size, which is why I THINK I had to get into the 16 bit range to get a large enough data pool for my needs.

If I'm sending with a 16 bit data range and my number happens to be 15 bits, the decoder on the other side says unknown type and gives me gobblygook on the other side.

Thanks so much for helping me process through this.

mudmin:
If I'm sending with a 16 bit data range and my number happens to be 15 bits, the decoder on the other side says unknown type and gives me gobblygook on the other side.

That just doesn't make sense as all numbers are internally stored in 8, 16 or 32 bit sizes (or even bigger). So the 15-bit value you provide occupies a 16-bit space with just a zero for bit 15.

Also your Sony library will be getting the value in the form of an int, which is a 16-bit value, and then just transmits the first 12 bits of that, ignoring the highest four. That's at least the exact behaviour you described above. If your value can fit in 10 bits, then it's simply sending zeroes for bits 10 and 11.

Now of course trying to transmit more (or less) bits than are expected on the other side is asking for trouble, but why going through the trouble of checking which bit is the highest that's set in your variable? Just send out the number of bits expected and ignore the rest.

Now if 12 bits (8 teams, 512 players or 16 team, 256 players) is not enough for you, and you really want to add a few more bits, dive into the libraries and find out where the number of bits is set on both the sending and receiving side, and change this. Add a bit or two there.