stefanos
stefanos

Reputation: 105

Efficient mapping from bits of one variable to another

I have 4 x Uint32 variables named lowLevelErrors1, lowLevelErrors2... up to 4. Each bit on those represent a low level error. I need to map them to a Uint64 variable named userErrors. Each bit of the userError represent an error shown to the user which can be set due to 1 or more low level errors. In other words, every low level error is mapped to 1 user error. 2 or more low level errors can be mapped to the same user error.

Let's scale it down to 2x Uint8 low level errors and 1x Uint8 user error so we can see an example.

Example: If any of the following low level errors is set {ERR_VOLT_LOW || ERR_NO_BATTERY || ERR_NOT_CHARGING} (which correspond to bit 0, bit 2 and bit 3 of lowLevelErrors1) then the user error US_ERR_POWER_FAIL is set (which is bit 5 of userErrors).

So the only way I could think of was to have a map array for each lowLevelErrors variable that will be used to map to the corresponding bit of the userErrors.

/* Let's say the lowLevelErrors have to be mapped like this:
lowLevelErrors1 bit maps to userError bit
        0                         5 
        1                         1
        2                         5
        3                         5
        4                         0
        5                         2
        6                         7
        7                         0

lowLevelErrors2 bits maps to userError bit
        0                         1
        1                         1
        2                         0
        3                         3
        4                         6
        5                         6
        6                         4
        7                         7
*/

Uint8 lowLevelErrors1 = 0;
Uint8 lowLevelErrors2 = 0;
Uint8 userErrors = 0;

Uint8 mapLLE1[8] = {5, 1, 5, 5, 0, 2, 7, 0};
Uint8 mapLLE2[8] = {1, 1, 0, 3, 6, 6, 4, 7};

void mapErrors(void)
{
    for (Uint8 bitIndex = 0; bitIndex < 8; i++)
    {
        if (lowLevelErrors1 && (1 << i))  //If error bit is set
        {
            userErrors |= 1 << mapLLE1[bitIndex];  //Set the corresponding user error
        }
    }

    for (Uint8 bitIndex = 0; bitIndex < 8; i++)
    {
        if (lowLevelErrors2 && (1 << i))  //If error bit is set
        {
            userErrors |= 1 << mapLLE2[bitIndex];  //Set the corresponding user error
        }
    }

}

The problem with this implementation is the need for the map arrays. I will need to have 4x uint8 array[32] = 128 uint8 variables and we are running low on memory on the microcontroller.

Is there any other way to implement the same functionality using less RAM?

Upvotes: 2

Views: 522

Answers (2)

TonyK
TonyK

Reputation: 17114

You have 128 input bits, each of which is mapped to a bit number from 0 to 63. So that is 128 * 6 = 768 bits of information, which needs at least 96 bytes of storage unless there is some regular pattern to it.

So you need at least 96 bytes; and even then, it would be stored as packed 6-bit integers. The code to unpack these integers might well cost more than the 32 bytes that you save by packing them.

So you basically have three choices: a 128-byte array, as you suggest; packed 6-byte integers; or some regular assignment of the error codes that is easier to unpack (which is not a possibility if the specific error code mapping is fixed).

Upvotes: 2

Mats Petersson
Mats Petersson

Reputation: 129314

Since you haven't given a complete example with ALL errors, it's hard to say what is the "best" method, but I would construct a table of "mask" and "value":

Something like this:

struct Translate
{
    uint32_t mask;
    // Maybe have mask[4]?
    uint64_t value;
};

// If not mask[4], the 
Translate table[] = 
{
    {  ERR_VOLT_LOW | ERR_NO_BATTERY | ERR_NOT_CHARGING, 
       // If mask[4] then add 3 more values here - expect typically zeros
       US_ERR_POWER_FAIL },
    ... 
};

I'm not sure which will make more sense, to have 4 different values in the table, or have 4 different tables - it would depend on how often your errors from LowLevel1 and LowLevel2, LowLevel2 and LowLevel4, etc are mapping to the same error. But by storing a map of multiple errors to one value, you should.

Now, once we have a data structure, the code becomes something like:

 for(auto a : table)
 {
     if (a.mask & lowLevelErrors1)
     {
       userErrror |= a.value; 
     }
  }

Upvotes: 0

Related Questions