How to return a bool array ?

Hello !

I am trying to create a function that receives a String as parameter and returns a bool array.

I am using an ESP32.

#include <Arduino.h>

bool* getWiegand(String id_string) {
  bool cardID[24] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  id_string.trim();
  unsigned int id = id_string.toInt();
  

  for (int i = 23; i >= 0; --i) {
    cardID[i] = id & 1;
    id >>= 1;
  }
  return cardID;
}

void setup() {

  bool *a = getWiegand("86840");
  for(int i=0; i<24; i++) {
    Serial.print(a[i]);
  }
}

void loop() {}

But this ends up with a Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled and endless reboots.

Any ideas ? Is this even possible ?
Thank you.

Why would you expand a 32 bit (4 byte) value into a 24 byte array? "cardID" is a static, local declaration and thus it cannot be used as a return value. The array must either be dynamically allocated (bool* cardID = new bool[24] - remember to release the memory when no longer used) or declared as a global variable.

Danois90:
Why would you expand a 32 bit (4 byte) value into a 24 byte array?

I what now ?

Danois90:
"cardID" is a static, local declaration and thus it cannot be used as a return value. The array must either be dynamically allocated (bool* cardID = new bool[24] - remember to release the memory when no longer used) or declared as a global variable.

I was currently looking into that and changed my declaration as such:
bool* cardID = new bool[24]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
but I don't know where to delete it.
If I write delete[] cardID; outside the function, then cardID; is not defined.

When you are using a CardID it is most common to pass it in a 32-bit unsigned integer. It would be easy to return a uint32_t and convert it to booleans in the calling function.

uint32_t getWiegand(String id_string) 
{
  id_string.trim();
  uint32_t id = id_string.toInt();
  return id;
}


void setup() 
{
  uint32_t id = getWiegand("86840");
  for (int i = 0; i < 24; i++) 
  {
    Serial.print((id & (1 << (23-i))) ? '1' : '0');
  }
}


void loop() {}

If you don't need leading zeroes:

void setup() 
{
  uint32_t id = getWiegand("86840");
  Serial.print(id, BIN);
}

I am having difficulty figuring out from your uncommented code what in the world you are trying to do?

Your code looks OK for returning the bool array, though function arguments is still a bit fuzzy for me. When I run your code with one itty-bitty modification, I get:

000000001282552556313213264802552556324422625463

Is that what you expected?

Here's my change to your code:

void setup() {
  Serial.begin(115200);
  Serial.println();

Danois90:
"cardID" is a static, local declaration and thus it cannot be used as a return value. The array must either be dynamically allocated (bool* cardID = new bool[24] - remember to release the memory when no longer used) or declared as a global variable.

Not quite. Currently it's an "automatic" (stack) local variable. If you make it a 'static' local variable, you can return a pointer to it.

GeorgeFlorian:
I what now ?

Although boolean variables only hold 0 or 1 they are stored as bytes.

The fundamental problem is that once a function has finished all the resources it created should be released with a few exceptions. These exceptions create a lot of issues because you must release the resources somewhere else in your code. This is often forgotten when the code gets modified and programs get memory leaks. So, the convention is to create a resource in your case the array in the calling function and provide the address to the called function. The called function will then fill the array and only return a success/fail value.

So, your function call needs to get at least two parameters. The string and the array address to put the data in. Often you see a third parameter telling the called function how large the array/buffer is.

If you maintain "cardID" as a 32 bit integer (uint32_t), then you can use bitRead() to get the "boolean" values for each "index" / bit. It is much easier to handle like that :slight_smile:

gfvalvo:
Not quite. Currently it's an "automatic" (stack) local variable. If you make it a 'static' local variable, you can return a pointer to it.

Agreed, using "static" to describe the array is misleading. Using "static" in the declaration would only allow one instance of the array which could cause problems. Then I would rather pass an array as argument - if I really had to use an array.

I am trying to transform any decimal number in the range of 1 and 2^24-1 into a 24-bit binary number that I put into cardID.

For example: 86840 should return 000000010101001100111000. Next I would like to take the first 8 bits and the last 16 bits, transform them in their decimal form and store them in other variables. Now the remaining thing to do is to take the whole binary number and add its parity bits to transform it in a 26 bit Wiegand number, following the Wiegand protocol.

My ultimate goal is to make a class called Wiegand that has methods that does all this stuff.

For example:

Wiegand card("86840");
Serial.println(card.getCardID()); // should print 00121304
card.getFacilityCode(); // should print 1
// etc

GeorgeFlorian:
I am trying to transform any decimal number in the range of 1 and 2^24-1 into a 24-bit binary number that I put into cardID.

For example: 86840 should return 000000010101001100111000. Next I would like to take the first 8 bits and the last 16 bits, transform them in their decimal form and store them in other variables.

uint32_t cardID = 86840;
uint8_t  first8bits = cardID >> 16;    // first8bits = 1
uint16_t last16bits = cardID & 0xffff; // last16bits = 21304 (0101001100111000 in binary)