Mapping an array to a decimal number from a binary number

I’m working on an IR-based pulse interpreter and I’m stuck.

Essentially, I would like the Arduino to receive a fully-decoded signal which then converts to numbers. The signal being received is a 16-bit string of binary. I can get it to tell me the numbers in binary without issue.

However, what I’m lacking is converting the array of binary pulses (interpreted to 1’s and 0’s) into a decimal number in a way which doesn’t take up 48 lines of code.

I was doing this:

#define irRead   4 // IR sensor
int irLen    =  600; // Pulse length, in microseconds
int irHeader =    7; // Header length, in pulses
int irGap    =  500; // Time between transmissions, in microseconds
// Data processing holders
int irRcv[17];          // Size in bits of one transmission
int irRetain    =   10; // Number of Rx to retain
// Byte 1
int irUnit[10];         // This needs to match irRetain length.
// Byte 2
int irCmd[10];         // Also has to match irRetain.
// Parity bit
int irParity[10];       // Also has to match irRetain.

/* Other sooper-sekrit programming stuffs removed... okay, really just for space's sake. */

void readIRData(){
  int irError = 0; // Just so we can make sure...
  int irTmp[17];   // Holder for length values.
  if(digitalRead(irRead) == LOW){
    for(int i = 1; i <= 17; i++){ // Ensures it's a full transmission
      // Wait for a pulse, then record its timings in microsec
      irTmp[i] = pulseIn(irRead,LOW,irGap);
    }
    for(int i = 1; i <= 17; i++){
      // Examine the received pulses: is it 0 or 1?
      if(irTmp[i] > (irLen - 200) && irTmp[i] < (irLen + 200)){
        irRcv[i] = 0;
      } 
      else if(irTmp[i] > ((irLen * 2) - 200) && irTmp[i] < ((irLen * 2) + 200 )){
        irRcv[i] = 1;
      }
    }
    byteParity = 0;
    for(int i = 1; i <= 16; i++){
      if(irRcv[i] == 1){
        byteParity++;
      }
      if(irRcv[i] > 1){
        irError = 1; // If it's not 0 or 1, it's an error.
      }
      byteParity = byteParity >> 0 & B1; // Bitwise shift check
      if(byteParity != irRcv[33]){
        // Error checking... it's not a real signal.
        irError = 1;
      }
      if(irError == 0){
        irData();
      }
    }
  }
}

void irData(){
  // Code I need would go here.
}

Now that I have it all in 1’s and 0’s, is there an efficient way to cast these as ordinary decimal numbers in the irData() function, so that I can then work with them easily? The data should go into the irUnit and irCmd arrays as single decimal numbers, at position 0 (I’ve shifted all of the arrays and am just overwriting position 0 in each case, so that there’s a rotation without trying to remove something from the stack, which isn’t possible in C++ arrays).

I would like this to take up fewer than 20 lines, max, but if it works I’m not going to be picky!

I would like this to take up fewer than 20 lines, max

Why ?

Now that I have it all in 1's and 0's, is there an efficient way to cast these as ordinary decimal numbers in the irData() function, so that I can then work with them easily?

A for loop calling bitWrite() can do the job in 4 lines. Two, if you don't use (or count) the open and close curly braces around the body.

If you are receiving a 16-bit binary number why are you saving each bit as an INT in an array. Why not convert them to a number as they arrive by shifting the value one step each time? Something like this

int newVal = 0;
for (n = 0; n < 16; n++) {
   // get the next bit
   newVal = newVal + newBit;
   newVal = newVal << 1;
}

…R

UKHeliBob:

I would like this to take up fewer than 20 lines, max

Why ?

Because I'm running a very long sketch that's currently approaching 500 lines and I'm trying to force it to work on a little Uno R3 board... because I'm a sadist and I enjoy torturing the hardware.

PaulS:

Now that I have it all in 1's and 0's, is there an efficient way to cast these as ordinary decimal numbers in the irData() function, so that I can then work with them easily?

A for loop calling bitWrite() can do the job in 4 lines. Two, if you don't use (or count) the open and close curly braces around the body.

Ah hah! I hadn't considered that. I'll experiment.

Robin2:
If you are receiving a 16-bit binary number why are you saving each bit as an INT in an array. Why not convert them to a number as they arrive by shifting the value one step each time? Something like this

int newVal = 0;

for (n = 0; n < 16; n++) {
   // get the next bit
   newVal = newVal + newBit;
   newVal = newVal << 1;
}




...R

The thinking was to interpret the pulses as they come in, with regard to the length (allowing for variation in an IR-noisy environment), and I thought an array was going to be more efficient than bitwise calculations in this case, since what I really want is 2 bytes of 8-bit data to calculate a unit ID (the source, which is used for authorizing the command) and then a command… was that not correct?

So… in trying to think through this:

void irData(){
  for(t = 0,t < 8,t++){
    bitWrite(irUnit[0],t,irRcv[t]); // Construct the first byte.
  }
  for(t = 8,t < 16,t++){
    bitWrite(irCmd[0],t,irRcv[t]); // Construct the second byte.
  }
  bitWrite(irParity[0],16,irRcv[16]);
}

The question I have is now whether or not those are the right values…

Yes, something is off, and I'm not sure what. :-/

The question I have is now whether or not those are the right values...

The for loops are wrong. The clauses of a for loop are separated by semicolons, not commas.

In the second for loop, do you really want to be setting bits 8, 9, 10, etc.? Or, do you want to be setting bits 0, 1, 2, etc?

I don't think you want to be setting bit 17 of irParity.

Why are irPariry, irUnit, and irCmd arrays?

PaulS: The for loops are wrong. The clauses of a for loop are separated by semicolons, not commas.

In the second for loop, do you really want to be setting bits 8, 9, 10, etc.? Or, do you want to be setting bits 0, 1, 2, etc?

I don't think you want to be setting bit 17 of irParity.

Why are irPariry, irUnit, and irCmd arrays?

Woops... I knew that semicolons were needed. I've been up all night, coding different parts of this project (there are 8 devices in the project, total, and I'm doing all of the receiving devices).

irRcv is 17 bits in length: it carries a unit ID, a command, and a parity bit. I thought putting the numbers into an array would be simpler for handling, and it would allow the unit to determine if the signal is valid, one bit at a time. If the signal received is outside of tolerance, then it's neither a 1 nor a 0; it's invalid data and will not be interpreted.

Again, I thought it was easier to measure the pulse length as a number in microseconds, then run a calculation to see if it's actually within tolerance. If it's within tolerance, then it's a bit. Outside of tolerance, it's an error and not interpreted.

Making this an array means that I could validate whether or not it's actually a signal, because the environment is likely to be IR-noisy with all 8 devices working. I didn't want it to try to interpret signals that were actually just noise. An array seemed much simpler to work with as a solution.

So would this work in the second byte to extract the correct bit values?

void irData(){
  for(t = 0;t < 8;t++){
    bitWrite(irUnit[0],t,irRcv[t]); // Construct the first byte.
  }
  for(t = 8;t < 16;t++){
    bitWrite(irCmd[0],(t - 8),irRcv[t]); // Construct the second byte.
  }
  bitWrite(irParity[0],16,irRcv[16]);
}

Or should I add an int handler to do the math on t?

Had to declare t as an int, forgot that.

Did declare b as an in, as t - 8 ... and it compiled.

Now I have to get some sleep, and I'll figure out if it's right later, lol.

RedHeron:

UKHeliBob:

I would like this to take up fewer than 20 lines, max

Why ?

Because I'm running a very long sketch that's currently approaching 500 lines and I'm trying to force it to work on a little Uno R3 board... because I'm a sadist and I enjoy torturing the hardware.

But there is not a direct relationship between the number of lines in the source code and the size of the program that the compiler produces.

void irData(){
  for(t = 0;t < 8;t++){
    bitWrite(irUnit[0],t,irRcv[t]); // Construct the first byte.
  }
  for(t = 8;t < 16;t++){
    bitWrite(irCmd[0],(t - 8),irRcv[t]); // Construct the second byte.
  }
  bitWrite(irParity[0],16,irRcv[16]);
}

Do you really want to be setting bit 16 of irParity[ 0 ]?

I thought putting the numbers into an array would be simpler for handling,

How, since you always put them in position 0?

and it would allow the unit to determine if the signal is valid, one bit at a time.

That doesn’t hold water. It is no different comparing the bits in the 0th element of an array vs. comparing the bits in a scalar variable.

Unless you are talking about the “bits” in the irRcv array, in which case you still haven’t explained why irUnit, irCmd, and irParity are arrays.

RedHeron: in this case, since what I really want is 2 bytes of 8-bit data to calculate a unit ID

So after you have 8 bits start another byte.

Or split the INT into two separate bytes.

...R

PaulS: Unless you are talking about the "bits" in the irRcv array, in which case you still haven't explained why irUnit, irCmd, and irParity are arrays.

Oh! I didn't understand what you were asking before.

I have held 10 past results for review, and (outside the code I displayed) I've moved each of the items down the array and then overwritten the last and put the new value into the first. This is for retransmission to another unit, and not really a part of this problem.

Oh! I didn't understand what you were asking before.

I have held 10 past results for review, and (outside the code I displayed) I've moved each of the items down the array and then overwritten the last and put the new value into the first. This is for retransmission to another unit, and not really a part of this problem.

OK. Thanks for explaining.

Yeah... so, I'm totally using the array in the first part, and keeping the bitWrite() in the second.

Also: when someone posts something like a vague and silly question (e.g., 'why?') resulted in a vague and silly answer. If you don't like it, tough. You can always toddle off to another thread.

I wanted it less than 20 lines, because I saw that the 20-line solution I had was sloppy and easily improved. But I didn't know how to improve it, so I asked here.

I also commented that it was 500 lines with the hope you'd think about it and consider that I didn't want to have to go through that many lines of code if there turned out to be some kind of math or parity issue.

Answering the question didn't require more information than I provided. In fact, I offered a little too much information as it was, which added to the confusion. But ultimately, the suggestion of bitWrite() led me to the solution I needed, and has actually improved other parts of the code.

So, while Robin2's comments were unhelpful, PaulS's suggestion got me going the direction I needed to go.

I may even post the finished code into github once I'm done, if it's awesome enough. Which it's not yet. I'm still working on it.

I've noticed there is a tendency to be critical of the works in progress. It's why I don't often post here.

RedHeron: So, while Robin2's comments were unhelpful,

Why?

I am asking so I can learn - perhaps I have misunderstood your requirement? It would not be the first time !

By the way I am not so dumb as to assume you MUST use my solution. There are usually as many ways to do something as there are programmers.

...R