如何制作3D面具

时间:2021-12-15 14:59:05

Currently I meet one technique issue, which makes me want to improve the previous implementation, the situation is:

目前我遇到一个技术问题,这让我想改进以前的实现,情况是:

I have 5 GPIO pins, I need use these pins as the hardware identifier, for example:

我有5个GPIO引脚,我需要使用这些引脚作为硬件标识符,例如:

pin1: LOW
pin2: LOW
pin3: LOW
pin4: LOW
pin5: LOW

this means one of my HW variants, so we can have many combinations. In previous design, the developer use if-else to implement this, just like:

这意味着我的一个硬件变种,所以我们可以有很多组合。在以前的设计中,开发人员使用if-else来实现它,就像:

if(PIN1 == LOW && ... && ......&& PIN5 ==LOW) 
{
    HWID = variant1;
}
else if( ... )
{
}
...
else
{
}

but I think this is not good because it will have more than 200 variants, and the code will become to long, and I want changed it to a mask. The idea is I treat this five pins as a five bits register, and because I can predict which variant I need to assign according to GPIOs status(this already defined by hardware team, they provide a variant list, with all these GPIO pins configuration), therefore, the code may look like this:

但我认为这不好,因为它将有200多个变种,代码将变得很长,我想把它改成掩码。我的想法是将这五个引脚视为五位寄存器,因为我可以预测我需要根据GPIO状态分配哪个变量(这已由硬件团队定义,它们提供变量列表,所有这些GPIO引脚配置)因此,代码可能如下所示:

enum{
    variant 0x0    //GPIO config 1
    ...
    variant 0xF3   //GPIO config 243
}

then I can first read these five GPIO pins status, and compare to some mask to see if they are equal or not.

然后我可以先读取这五个GPIO引脚的状态,并与一些掩码进行比较,看它们是否相等。

Question

However, for GPIO, it has three status, namely: LOW, HIGH, OPEN. If there is any good calculation method to have a 3-D mask?

但是,对于GPIO,它有三种状态,即:LOW,HIGH,OPEN。如果有任何好的计算方法来制作3-D掩模?

2 个解决方案

#1


1  

You have 5 pins of 3 states each. You can approach representing this in a few ways.

你有5个引脚,每个3个状态。您可以通过几种方式表示这一点。

First, imagine using this sort of framework:

首先,想象一下使用这种框架:

#define LOW (0)
#define HIGH (1)
#define OPEN (2)

uint16_t config = PIN_CONFIG(pin1, pin2, pin3, pin4, pin5);

if(config == PIN_CONFIG(LOW, HIGH, OPEN, LOW, LOW))
{
    // do something
}

switch(config) {
    case PIN_CONFIG(LOW, HIGH, OPEN, LOW, HIGH):
        // do something;
        break;
}

uint16_t config_max = PIN_CONFIG(OPEN, OPEN, OPEN, OPEN, OPEN);
uint32_t hardware_ids[config_max + 1] = {0};

// init your hardware ids
hardware_ids[PIN_CONFIG(LOW, HIGH, HIGH, LOW, LOW)] = 0xF315;
hardware_ids[PIN_CONFIG(LOW, LOW, HIGH, LOW, LOW)] = 0xF225;

// look up a HWID
uint32_t hwid = hardware_ids[config];

This code is just the sort of stuff you'd like to do with pin configurations. The only bit left to implement is PIN_CONFIG

这段代码就是你想要的引脚配置。剩下要实现的唯一一点是PIN_CONFIG


Approach 1

The first approach is to keep using it as a bitfield, but instead of 1 bit per pin you use 2 bits to represent each pin state. I think this is the cleanest, even though you're "wasting" half a bit for each pin.

第一种方法是继续将其用作位域,但是每个引脚使用2位来代替每个引脚状态,而不是每个引脚使用1位。我认为这是最干净的,即使你为每个引脚“浪费”了一半。

#define PIN_CLAMP(x) ((x) & 0x03)
#define PIN_CONFIG(p1, p2, p3, p4, p5)  \\
  (PIN_CLAMP(p1) &                      \\
  (PIN_CLAMP(p2) << 2) &                \\
  (PIN_CLAMP(p3) << 4) &                \\
  (PIN_CLAMP(p4) << 6) &                \\
  (PIN_CLAMP(p5) << 8))

This is kind of nice because it leaves room for a "Don't care" or "Invalid" value if you are going to do searches later.

这有点不错,因为如果您稍后要进行搜索,它会为“请勿关注”或“无效”值留出空间。


Approach 2

Alternatively, you can use arithmetic to do it, making sure you use the minimum amount of bits necessary. That is, ~1.5 bits to encode 3 values. As expected, this goes from 0 up to 242 for a total of 3^5=243 states. Without knowing anything else about your situation I believe this is the smallest complete encoding of your pin states. (Practically, you have to use 8 bits to encode 243 values, so it's higher 1.5 bits per pin)

或者,您可以使用算术来执行此操作,确保使用所需的最小位数。也就是说,~1.5位来编码3个值。正如预期的那样,从0到242,总共3 ^ 5 = 243个状态。在不了解您的情况的情况下,我相信这是您的引脚状态的最小完整编码。 (实际上,您必须使用8位来编码243个值,因此每个引脚的高位为1.5位)

#define PIN_CLAMP(x) ((x) % 3) /* note this should really assert */
#define PIN_CONFIG(p1, p2, p3, p4, p5)  \\
  (PIN_CLAMP(p1) &                      \\
  (PIN_CLAMP(p2) * 3) &                 \\
  (PIN_CLAMP(p3) * 9) &                 \\
  (PIN_CLAMP(p4) * 27) &                \\
  (PIN_CLAMP(p5) * 81))

Approach 1.1

If you don't like preprocessor stuff, you could use functions a bit like this:

如果你不喜欢预处理器的东西,你可以使用这样的函数:

enum PinLevel (low = 0, high, open);

void set_pin(uint32_t * config, uint8_t pin_number, enum PinLevel value) {
    int shift = pin_number * 2; // 2 bits
    int mask = 0x03 << shift; // 2 bits set to on, moved to the right spot
    *config &= ~pinmask;
    *config |= (((int)value) << shift) & pinmask;
}

enum PinLevel get_pin(uint32_t config, uint8_t pin_number) {
    int shift = pin_number * 2; // 2 bits
    return (enum PinLevel)((config >> shift) & 0x03);
}

This follows the first (2 bit per value) approach.

这遵循第一个(每个值2位)方法。


Approach 1.2

YET ANOTHER WAY using C's cool bitfield syntax:

使用C的酷位域语法的另一种方式:

struct pins {
    uint16_t pin1 : 2;
    uint16_t pin2 : 2;
    uint16_t pin3 : 2;
    uint16_t pin4 : 2;
    uint16_t pin5 : 2;
};

typedef union pinconfig_ {
    struct pins pins;
    uint16_t value;
} pinconfig;

pinconfig input;
input.value = 0; // don't forget to init the members unless static

input.pins.pin1 = HIGH;
input.pins.pin2 = LOW;

printf("%d", input.value);

input.value = 0x0003;
printd("%d", input.pins.pin1);

The union lets you view the bitfield as a number and vice versa.

联合允许您将位域视为数字,反之亦然。

(note: all code completely untested)

(注意:所有代码完全未经测试)

#2


1  

This is my suggestion to solve the problem

这是我解决问题的建议

#include<stdio.h>

#define LOW 0
#define HIGH 1
#define OPEN 2

#define MAXGPIO 5

int main()
{
    int gpio[MAXGPIO] = { LOW, LOW, OPEN, HIGH, OPEN };

    int mask = 0;

    for (int i = 0; i < MAXGPIO; i++)
        mask = mask << 2 | gpio[i];  

    printf("Masked: %d\n", mask);
    printf("Unmasked:\n");

    for (int i = 0; i < MAXGPIO; i++)
        printf("GPIO %d = %d\n", i + 1, (mask >> (2*(MAXGPIO-1-i))) & 0x03); 

    return 0;
}

A little explanation about the code.

关于代码的一点解释。

Masking
I am using 2 bits to save each GPIO value. The combinations are:

屏蔽我使用2位来保存每个GPIO值。组合是:

  • 00: LOW
  • 00:低
  • 01: HIGH
  • 01:高
  • 02: OPEN
  • 02:开放
  • 03 is Invalid
  • 03无效

I am iterating the array gpio (where I have the acquired values) and creating a mask in the mask variable shifting left 2 bits and applying an or operation.

我正在迭代数组gpio(我有获取的值)并在掩码变量中创建一个掩码,左移2位并应用或操作。

Unmasking
To get the initial values I am just making the opposite operation shifting right 2 bits multiplied by the amount of GPIO - 1 and masking with 0x03

取消屏蔽要获取初始值,我只是将相反的操作右移2位乘以GPIO - 1的数量,并用0x03屏蔽

I am applying a mask with 0x03 because those are the bit I am interested.

我正在应用一个带有0x03的掩码,因为那些是我感兴趣的位。

This is the result of the program

这是该计划的结果

$ cc -Wall test.c -o test;./test
Masked: 38
Unmasked:
GPIO 1 = 0
GPIO 2 = 0
GPIO 3 = 2
GPIO 4 = 1
GPIO 5 = 2

Hope this helps

希望这可以帮助

#1


1  

You have 5 pins of 3 states each. You can approach representing this in a few ways.

你有5个引脚,每个3个状态。您可以通过几种方式表示这一点。

First, imagine using this sort of framework:

首先,想象一下使用这种框架:

#define LOW (0)
#define HIGH (1)
#define OPEN (2)

uint16_t config = PIN_CONFIG(pin1, pin2, pin3, pin4, pin5);

if(config == PIN_CONFIG(LOW, HIGH, OPEN, LOW, LOW))
{
    // do something
}

switch(config) {
    case PIN_CONFIG(LOW, HIGH, OPEN, LOW, HIGH):
        // do something;
        break;
}

uint16_t config_max = PIN_CONFIG(OPEN, OPEN, OPEN, OPEN, OPEN);
uint32_t hardware_ids[config_max + 1] = {0};

// init your hardware ids
hardware_ids[PIN_CONFIG(LOW, HIGH, HIGH, LOW, LOW)] = 0xF315;
hardware_ids[PIN_CONFIG(LOW, LOW, HIGH, LOW, LOW)] = 0xF225;

// look up a HWID
uint32_t hwid = hardware_ids[config];

This code is just the sort of stuff you'd like to do with pin configurations. The only bit left to implement is PIN_CONFIG

这段代码就是你想要的引脚配置。剩下要实现的唯一一点是PIN_CONFIG


Approach 1

The first approach is to keep using it as a bitfield, but instead of 1 bit per pin you use 2 bits to represent each pin state. I think this is the cleanest, even though you're "wasting" half a bit for each pin.

第一种方法是继续将其用作位域,但是每个引脚使用2位来代替每个引脚状态,而不是每个引脚使用1位。我认为这是最干净的,即使你为每个引脚“浪费”了一半。

#define PIN_CLAMP(x) ((x) & 0x03)
#define PIN_CONFIG(p1, p2, p3, p4, p5)  \\
  (PIN_CLAMP(p1) &                      \\
  (PIN_CLAMP(p2) << 2) &                \\
  (PIN_CLAMP(p3) << 4) &                \\
  (PIN_CLAMP(p4) << 6) &                \\
  (PIN_CLAMP(p5) << 8))

This is kind of nice because it leaves room for a "Don't care" or "Invalid" value if you are going to do searches later.

这有点不错,因为如果您稍后要进行搜索,它会为“请勿关注”或“无效”值留出空间。


Approach 2

Alternatively, you can use arithmetic to do it, making sure you use the minimum amount of bits necessary. That is, ~1.5 bits to encode 3 values. As expected, this goes from 0 up to 242 for a total of 3^5=243 states. Without knowing anything else about your situation I believe this is the smallest complete encoding of your pin states. (Practically, you have to use 8 bits to encode 243 values, so it's higher 1.5 bits per pin)

或者,您可以使用算术来执行此操作,确保使用所需的最小位数。也就是说,~1.5位来编码3个值。正如预期的那样,从0到242,总共3 ^ 5 = 243个状态。在不了解您的情况的情况下,我相信这是您的引脚状态的最小完整编码。 (实际上,您必须使用8位来编码243个值,因此每个引脚的高位为1.5位)

#define PIN_CLAMP(x) ((x) % 3) /* note this should really assert */
#define PIN_CONFIG(p1, p2, p3, p4, p5)  \\
  (PIN_CLAMP(p1) &                      \\
  (PIN_CLAMP(p2) * 3) &                 \\
  (PIN_CLAMP(p3) * 9) &                 \\
  (PIN_CLAMP(p4) * 27) &                \\
  (PIN_CLAMP(p5) * 81))

Approach 1.1

If you don't like preprocessor stuff, you could use functions a bit like this:

如果你不喜欢预处理器的东西,你可以使用这样的函数:

enum PinLevel (low = 0, high, open);

void set_pin(uint32_t * config, uint8_t pin_number, enum PinLevel value) {
    int shift = pin_number * 2; // 2 bits
    int mask = 0x03 << shift; // 2 bits set to on, moved to the right spot
    *config &= ~pinmask;
    *config |= (((int)value) << shift) & pinmask;
}

enum PinLevel get_pin(uint32_t config, uint8_t pin_number) {
    int shift = pin_number * 2; // 2 bits
    return (enum PinLevel)((config >> shift) & 0x03);
}

This follows the first (2 bit per value) approach.

这遵循第一个(每个值2位)方法。


Approach 1.2

YET ANOTHER WAY using C's cool bitfield syntax:

使用C的酷位域语法的另一种方式:

struct pins {
    uint16_t pin1 : 2;
    uint16_t pin2 : 2;
    uint16_t pin3 : 2;
    uint16_t pin4 : 2;
    uint16_t pin5 : 2;
};

typedef union pinconfig_ {
    struct pins pins;
    uint16_t value;
} pinconfig;

pinconfig input;
input.value = 0; // don't forget to init the members unless static

input.pins.pin1 = HIGH;
input.pins.pin2 = LOW;

printf("%d", input.value);

input.value = 0x0003;
printd("%d", input.pins.pin1);

The union lets you view the bitfield as a number and vice versa.

联合允许您将位域视为数字,反之亦然。

(note: all code completely untested)

(注意:所有代码完全未经测试)

#2


1  

This is my suggestion to solve the problem

这是我解决问题的建议

#include<stdio.h>

#define LOW 0
#define HIGH 1
#define OPEN 2

#define MAXGPIO 5

int main()
{
    int gpio[MAXGPIO] = { LOW, LOW, OPEN, HIGH, OPEN };

    int mask = 0;

    for (int i = 0; i < MAXGPIO; i++)
        mask = mask << 2 | gpio[i];  

    printf("Masked: %d\n", mask);
    printf("Unmasked:\n");

    for (int i = 0; i < MAXGPIO; i++)
        printf("GPIO %d = %d\n", i + 1, (mask >> (2*(MAXGPIO-1-i))) & 0x03); 

    return 0;
}

A little explanation about the code.

关于代码的一点解释。

Masking
I am using 2 bits to save each GPIO value. The combinations are:

屏蔽我使用2位来保存每个GPIO值。组合是:

  • 00: LOW
  • 00:低
  • 01: HIGH
  • 01:高
  • 02: OPEN
  • 02:开放
  • 03 is Invalid
  • 03无效

I am iterating the array gpio (where I have the acquired values) and creating a mask in the mask variable shifting left 2 bits and applying an or operation.

我正在迭代数组gpio(我有获取的值)并在掩码变量中创建一个掩码,左移2位并应用或操作。

Unmasking
To get the initial values I am just making the opposite operation shifting right 2 bits multiplied by the amount of GPIO - 1 and masking with 0x03

取消屏蔽要获取初始值,我只是将相反的操作右移2位乘以GPIO - 1的数量,并用0x03屏蔽

I am applying a mask with 0x03 because those are the bit I am interested.

我正在应用一个带有0x03的掩码,因为那些是我感兴趣的位。

This is the result of the program

这是该计划的结果

$ cc -Wall test.c -o test;./test
Masked: 38
Unmasked:
GPIO 1 = 0
GPIO 2 = 0
GPIO 3 = 2
GPIO 4 = 1
GPIO 5 = 2

Hope this helps

希望这可以帮助