Multiple booleans

Hi,

i’m working on a project where i need to send data to multiple divices with a specific id with a for loop or something.
I need a way to set which ID’s can be send and which can’t.

My first thought was to use 2 array’s. But this does not seem verry efficiant.

Example:

int array1[ARRAYSIZE] {1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1};
int IDS[ARRAYSIZE] {01, 20, 35, 12, 42, 88, 55, 74, 63, 23, 24, 44, 78, 05, 08, 10, 65, 22, 89, 99};

Is there a more efficiant way to do this?

But this does not seem verry efficiant.

Use the bits of a variable instead of array1 and certainly don't use int variables where the values will not exceed 255

You would halve the memory requirement by using byte rather than int for you data.

If the purpose is to iterate over the address array and send a corresponding value from the other array what you are doing seems sensible.

I would only use the bits in a byte if I was stuck for space - using bits makes the programming more complex and is unlikely to offer any performance advantage.

...R

Thanks for the answer!

The use of a struct with bit fields is probably the most efficient. A struct defines a new type that contains related information; e.g. first name, last name and phone number in a phonebook.

The struct in the below uses 1 bit of a byte to indicate enabled/disabled and the remaining 7 bits for the device ID. So you can have up to 127 device IDs.

struct ID
{
  byte enabled: 1;
  byte id: 7;
};

ID deviceIDs[] =
{
  { true, 33},
  { true, 34},
  { false, 12},
};


void setup() {

  Serial.begin(9600);
  Serial.print("size of deviceIDs: "); Serial.println(sizeof(deviceIDs));
  Serial.print("number of elements: "); Serial.println(sizeof(deviceIDs) / sizeof(deviceIDs[0]));

  for (int cnt = 0; cnt < sizeof(deviceIDs) / sizeof(deviceIDs[0]); cnt++)
  {
    Serial.print("device ID: "); Serial.print(deviceIDs[cnt].id);
    Serial.print(deviceIDs[cnt].enabled == true ? " enabled" : " disabled");
  }


}

void loop() {
  // put your main code here, to run repeatedly:

}

If 127 is not enough, you can change both elements of the struct to (unsigned) int and allocate up to 15 bits for the device ID.

Note:
compiles but not tested

If you use an array of bytes, you can have 256 unique device IDs, and a string( i.e. char array) can take care of that. A word is 65536 unique device IDs.

If the devices are ID’d in the range so that the booleans in their ID can be used as their broadcast group, you won’t need a second array of bytes or booleans or flags.

You can also broadcast to all devices, avoiding the need for IDs and booleans, and add a key to your data protocol that the connected devices will use to receive the data that is for them and filter out the data that they do not need to process.

sterretje:
The struct in the below uses 1 bit of a byte to indicate enabled/disabled and the remaining 7 bits for the device ID.

I had not come across this before. I presume the enabled: 1 is what tells it to use one bit etc

That certainly seems very efficient use of SRAM but I suspect there is a lot of underlying code to give effect to it so that it might not perform any better than using two arrays of bytes.

...R

Robin2:
That certainly seems very efficient use of SRAM but I suspect there is a lot of underlying code to give effect to it so that it might not perform any better than using two arrays of bytes.

The code is very lightweight. It's a simple boolean check.

This is how shift registers work.

It's used in MAC adresses, to differentiate registered from unregistered addresses, and to tell if they are unicast or multicast.

It's used in NTP protocol, the first byte is all booleans.

It's used in CIDR IP routing, I.E. Subnet Mask, which is only one example of bitmasking.

if (address && booleanMask == broadcastGroup) Serial.print(message);

Robin2:
I had not come across this before. I presume the enabled: 1 is what tells it to use one bit etc

That certainly seems very efficient use of SRAM but I suspect there is a lot of underlying code to give effect to it so that it might not perform any better than using two arrays of bytes.

...R

Never looked under the hood; I suspect simple bit masking and bit shifting.

I think Perehama meant

    if ((address & booleanMask) == broadcastGroup) Serial.print(message);

-dev:
I think Perehama meant

    if ((address & booleanMask) == broadcastGroup) Serial.print(message);

Yes!

for (int i=0; i <= 255; i++){
     address = addressArray[i];
     if (address & booleanMask == broadcastGroup) sendMessage(addressArray[i]);
}

sterretje:
Never looked under the hood; I suspect simple bit masking and bit shifting.

What I'm thinking is that if the values are in bytes to start with there will be no need for masking or shifting. So if one can afford the extra cost in SRAM the code using an array of bytes would probably run faster - admittedly only by a small amount.

Using a struct like that certainly keeps the program code nice and short.

...R

Robin2:
What I’m thinking is that if the values are in bytes to start with there will be no need for masking or shifting. So if one can afford the extra cost in SRAM the code using an array of bytes would probably run faster - admittedly only by a small amount.

Using a struct like that certainly keeps the program code nice and short.

…R

Do you mean?

for (int i=0; i <= 255; i++){
     if (array1[i]) sendMessage(IDS[i]);
}

?

Robin2:
What I'm thinking is that if the values are in bytes to start with there will be no need for masking or shifting. So if one can afford the extra cost in SRAM the code using an array of bytes would probably run faster - admittedly only by a small amount.

Using a struct like that certainly keeps the program code nice and short.

...R

Using 2 arrays to store related information is never a solution in my opinion; a struct or class is always preferable from a 'clean and readable' code perspective.

I forgot to answer part of your previous question; the number after the colon is indeed the number of bits. If you need e.g. a 2 bit, a second 2 bit and a 3 bit variable in a record it's also possible.

sterretje:
Using 2 arrays to store related information is never a solution in my opinion; a struct or class is always preferable from a 'clean and readable' code perspective.

I don't disagree with you except that arrays may be simpler for beginners.

What I was really trying to say is that a struct that contains two separate bytes would probably result in a faster program than a struct that forces two different pieces of data into a single byte.

...R

Robin2:
What I was really trying to say is that a struct that contains two separate bytes would probably result in a faster program than a struct that forces two different pieces of data into a single byte.

Can't disagree on that. Balance between memory usage and performance :slight_smile:

Use of bit fields is very common, by the way, in communication. Think e.g. ethernet and digital television.

Robin2:
I don't disagree with you except that arrays may be simpler for beginners.

What I was really trying to say is that a struct that contains two separate bytes would probably result in a faster program than a struct that forces two different pieces of data into a single byte.

...R

For only 2 bytes, you might be right, but if you need several pieces of data, each one or two bits long, putting them into a struct of 8,16,24 or 32 bits etc. will become more efficient as your parallel data points scale up. You can access them with pointers or by bitmasking.

Perehama:
For only 2 bytes, you might be right, but if you need several pieces of data, each one or two bits long, putting them into a struct of 8,16,24 or 32 bits etc. will become more efficient as your parallel data points scale up. You can access them with pointers or by bitmasking.

I am not denying the saving in SRAM by using bits rather than bytes. But all the Arduino instructions work on bytes so when multiple pieces of data are in a single byte the bits have to be extracted and converted to bytes before any decisions can be made. And that all takes CPU cycles.

As @sterretje says, it is a trade off between memory usage and performance. Or "no such thing as a free lunch" :slight_smile:

...R

Robin2:
the bits have to be extracted and converted to bytes before any decisions can be made

The bits are stored in bytes, within the struct, and require no extraction or conversion. Decisions are simply made on the byte based on the value of specific bits.
For example, we know that all numbers >= 10 && < 20 will have a 1 in the “tens” position.

Perehama:
The bits are stored in bytes, within the struct, and require no extraction or conversion. Decisions are simply made on the byte based on the value of specific bits.

I would be interested to see a short program that illustrates that.

…R