I am trying to do SNMP Set from host Linux to target system. But, instead of correct values, wrong values are getting set. After a bit of research, I made this table:
Hex representation of decimal value in Linux snmp
0 - 0x80 - 1000 0000 - 0 is converted to 128
1 - 0x40 - 0100 0000 - 1 is converted to 64
2 0x20 - 0010 0000 - 2 is converted to 32
3 0x10 - 0001 0000 - 3 is converted to 16
4 0x08 - 0000 1000 - 4 is converted to 8
5 0x04 - 0000 0100 - 5 is converted to 4
6 0x02 - 0000 0010 - 6 is converted to 2
7 0x01 - 0000 0001 - is converted to 1
Hex representation of decimal value in target system
0 - 0x00 - 0000 0000
1 - 0x01 - 0000 0001
2 0x02 - 0000 0010
3 0x03 - 0000 0011
4 0x04 - 0000 0100
5 0x05 - 0000 0101
6 0x06 - 0000 0110
7 0x07 - 0000 0111
I have two questions:
What could be the reason behind this issue?
Does anyone know how I can convert those Linux values to correct target values in a C program?
If I understand your question correctly, you receive a byte that encode 8 values (0 to 7) using a one-hot encoding. See https://en.wikipedia.org/wiki/One-hot (notice: your bit order seems reversed though).
If you simply put a one-hot encoded bit pattern into a byte variable on your target system, you'll not get the original value as your target system uses another encoding (probably 2's complement). In other words - a given bit pattern has different meanings in one-hot encoding and 2's complement encoding.
So the task is to convert the one-hot encoded values to equivalent values on your target system.
You could go for a simple switch-statement - like:
int main(void)
{
unsigned char linux_snmp_value = 0x20;
unsigned char target_value = 255;
switch(linux_snmp_value)
{
case 0x80:
target_value = 0;
break;
case 0x40:
target_value = 1;
break;
case 0x20:
target_value = 2;
break;
// Add the remaining cases here
default:
// Illegal value
// Add some error handling
break;
}
printf("Target value %d\n", target_value);
return 0;
}
If you prefer a loop, it could be something like:
int main(void)
{
unsigned char linux_snmp_value = 0x01;
unsigned char target_value = 0;
unsigned char mask = 0x80;
while (mask)
{
if (mask == linux_snmp_value) break;
++target_value;
mask = mask >> 1;
}
if (mask == 0)
{
// Illegal value
// Add some error handling
printf("ERROR\n");
return -1;
}
printf("Target value %d\n", target_value);
return 0;
}
If the portability is not the issue (for example you do not play to compile on the VAX or AVR8 machine) you can use machine instructions for it
asm (“bsrl %1, %0” : “=r” (position) : “r” (number));
you can also wrap it into nice inline function.
Similar instructions are available on ARM, MIPS, PIC and many other.
Related
I need to understand why i have to use &=(and) instead of |=(or).
I tried drawing and using it but had no success.
char readPin(char port,char pinNum){
switch(port){
case'A' :
return ((portA &=(1<<pinNum))>>pinNum);
case'B' :
return ((portB &=(1<<pinNum))>>pinNum);
case'C' :
return ((portC &=(1<<pinNum))>>pinNum);
case'D' :
return ((portD &=(1<<pinNum))>>pinNum);
case'E' :
return ((portE &=(1<<pinNum))>>pinNum);
case'F' :
return ((portF &=(1<<pinNum))>>pinNum);
}
}
I need to know why and is used instead of or.
portA &=(1<<pinNum)
returns a '1' at the position shifted to.
For Example: PinNum = 4, Port A.4 is Set / High, Port A.1 is Set / High
PortA - 0001 0010
(1<<pinNum) - 0001 0000 & // use bitwise and
portA &=(1<<pinNum) - 0001 0000 // Result (bit 1 is discarded due to and operation)
((portA &=(1<<pinNum))>>pinNum) - 0000 0001 // Result is shifted back to position 0
The returned value is a 1.
If you were to use use a bitwise or like:
portA |= (1<<pinNum)
You would return a non 0 value in all cases.
For Example: PinNum = 4, all Port A bits are low.
PortA - 0000 0000
(1<<pinNum) - 0001 0000 | // use bitwise or
portA |=(1<<pinNum) - 0001 0000 // Result (bit 4 is set)
((portA |=(1<<pinNum))>>pinNum) - 0000 0001 // Result is shifted back to position 0
The returned value is a 1.
As you can see, you tried to check for Pin 4 (which is not set) but you got a non zero result back (caused the masking bit).
The problem is SegmentOFF. For example if DATA[18] = 0x10 after calling SegmentON and I want to clear 6th bit of DATA[18]. Calling SegmentOFF clears all the bit and ends up DATA[18] = 0x00
What is wrong with the code.
unsigned char DATA[24];
unsigned int Segment2BitMap[48] =
{
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0204, 0x0300, 0x0302, 0x0307, 0x0600, 0x0601, 0x0602, 0x0603,
0x0604, 0x0605, 0x0606, 0x0607, 0x0804, 0x0900, 0x0902, 0x0907,
0x0C00, 0x0C01, 0x0C02, 0x0C03, 0x0C04, 0x0C05, 0x0C06, 0x0C07,
0x0E04, 0x0F00, 0x0F02, 0x0F07, 0x1200, 0x1201, 0x1202, 0x1203,
0x1204, 0x1205, 0x1206, 0x1207, 0x1404, 0x1500, 0x1502, 0x1507
};
void SegmentON(unsigned char Number)
{
unsigned int Data = Segment2BitMap[Number];
unsigned char UpperByte = (Data/256); //upper byte
unsigned char LowerByte = (Data%256 & 0x07); //lower byte
DATA[UpperByte] |= (0x01<<LowerByte);
}
void SegmentOFF(unsigned char Number)
{
unsigned int Data = Segment2BitMap[Number];
unsigned char UpperByte = (Data/256); //upper byte
unsigned char LowerByte = (Data%256 & 0x07); //lower byte
DATA[UpperByte] &= (0x01<<LowerByte);
}
int main()
{
SegmentON(40);
SegmentOFF(42);
}
1010 & 0101 == 0000
If you want to clear a specific bit and the rest should not be changed you have to invert it.
For 8 bit:
var &= (1<<2)^0xFF
This would set the 3rd least significant bit (1<<2) == 0x04 and then invert it with xor everything with ones
And then you apply that mask to var to set the 3rd bit to zero and the rest stays unchanged
This would be
var = var & 0b11111011
Ok, I mostly do ruby but the bit-wise operators look the same. (thus I'm assuming they are the same)
Lets work with a random number say 201. The binary representation is as follows:
1100 1001
To turn a bit on you simply do an OR operation.
201 |= 1<<2
The machine then bit shifts 0000 0001 2 steps to the left creating 0000 0100 and then makes an OR operation, if either of the numbers has a 1 at the nth position the resulting number will have a 1 at the same position.
1100 1001 # first input
0000 0100 # second input
1100 1101 # output => 209
So far so good, but when you try to set a bit to 0 using the AND operator something goes wrong.
201 &= 1<<2
Same as before but now it performs an AND operation instead. If the number share a 1 at the nth position the resulting number will have a 1 at that same position.
1100 1001 # first input
0000 0100 # second input
0000 0000 # output => 0
This happens because they have no common 1s. This can be solved in 2 ways. (both using the XOR operation)
The 'conditional' way.
if 209&(1<<2) != 0
209 ^= 1<<2
end
This code will do the following. if 201 and 1<<2 (8) is not equal to 0 then perform an exclusive or operation. In this case it is not equal to 0 so it will do as follows. Wherever the bits are the same it will put a 0 and where they differ it will put a 1.
1100 1101 # first input (209)
0000 0100 # second input (8)
1100 1001 # output => 201
The 'pure bit-wise' solution.
209&(255^(1<<2))
This will generate the following operation.
1100 1101 # first input (209)
1111 1011 # second input number (247)
1100 1001 # output => 201
We end up doing one extra bit operation, but we also loose the conditional. So it should be a bit faster. Get it bit, hehe. The code here can't directly be implemented in c, but the principal should be the same.
PS Your definition of the lower byte looks a bit odd, you are aware that it will only return the first 3 bits, right?
Hope it helps.
I am trying to select bits [0:2] and bits [6:8] of the bit-string 1010000000001. Bits [0:2] are 001 and bits [6:8] are 000. I tried to select these bits with:
int instr = 0x1401;
int src2 = (instr & 0x0006); //get bits [2:0]
int src1 = (instr & 0x01C0) >> 6; //get bits [6:8]
printf("%04x, %04x",src2, src1);
However I am getting that src1 and src2 are both 0000. Can someone please help me understand what I am doing incorrectly so I can select bits [0:2] and [6:8]?
Look at this code:
#include <stdio.h>
int main (void) {
unsigned instr = 0x1401;
unsigned src2 = instr & 0x0007; // 7 in hex == 0000 0000 0111 in binary
unsigned src1 = (instr & 0x01C) >> 6; // 1C in hex == 0001 1100 0000 in binary
printf("%04x, %04x", src2, src1);
}
It masks out the desired bits in instr and shifts them by the correct offset. Also, when doing bit manipulation, unsigned types are preferred.
It's easier to just write a function to calculate any arbitrary bit slice (here using 1 rather than 0 as the least significant bit):
#include <stdio.h>
#include <assert.h>
int bit_select(int num, size_t start, size_t end)
{
assert(end >= start);
const int mask = (1 << (end-start+1)) - 1;
const int shift = start - 1;
return (num & (mask << shift)) >> shift;
}
int main(void)
{
printf("Bits 1...3 of 01100101: %d\n", bit_select(0x65, 1, 3));
printf("Bits 3...3 of 01100101: %d\n", bit_select(0x65, 3, 3));
printf("Bits 4...4 of 01100101: %d\n", bit_select(0x65, 4, 4));
printf("Bits 3...7 of 01100101: %d\n", bit_select(0x65, 3, 7));
return 0;
}
with output:
paul#horus:~/src/sandbox$ ./bitselect
Bits 1...3 of 01100101: 5
Bits 3...3 of 01100101: 1
Bits 4...4 of 01100101: 0
Bits 3...7 of 01100101: 25
paul#horus:~/src/sandbox$
From what I can see if you get the result from 0x1401 & 0x0006 you get 0 and you get the same from 0x1401 & 0x01c0. The bit shift you do on src1 is just 0 shift right 6 bits which is still 0.
Because you provided a wrong mask.
To make life easier if you are using gcc, just provide binary literal rather than hex version so that you can see what you are masking off without pain:
unsigned src2 = instr & 0b111;
int instr = 0x1401;
//results in instr containing (ignoring endian)
//0x00001401
//or in binary
//0b0000 0000 0000 0000 0001 0100 0000 0001
//extracting bits 2:0 is normally done by:
int src2 = instr & 0x00000007;
//extracting bits 8:6 is normally done by:
int src1 = (instr & 0x000001C0) >> 6;
//note that if bit 31 is to be extracted,
//the bit shifting will not work
//due to sign propagation of a negative number
How can i map numbers like this:
1 => 0x01;
2 => 0x03;
3 => 0x07;
4 => 0x0F;
....
8 => 0xFF;
I have only 8 numbers to map and i need this for my RT embedded system so the solution must be efficient.
Is there a way to implement this using ENUM or DEFINE?
I don't want to use switch statement. Should i use an array:
BYTE bMap[8] =
{
0x01,
0x03,
0x07,
0x0F,
....
0xFF,
}
or is there another way?
Thank you! Max.
The two most obvious solutions would be:
Use an array. const uint8_t masks[] = { 1, 3, ... }.
Your mask seems to be "the i + 1 rightmost bits should be set", so you can trivally compute that at runtime using (1 << (i + 1)) - 1 which is easier to implement and less error-prone.
There's nothing wrong with using the lookup table to get your numbers but you could consider another approach.
If you're simply looping through those values in order, each one can be obtained by left-shifting the previous and setting the low order bit to 1:
0000 0001 (x01)
<< 1: 0000 0010
| 1: 0000 0011 (x03)
<< 1: 0000 0110
| 1: 0000 0111 (x07)
<< 1: 0000 1110
| 1: 0000 1111 (x0f)
<< 1: 0001 1110
| 1: 0001 1111 (x1f)
So, something like:
for (unsigned int i = 1; i < 0x100; i = (i << 1) | 1) ...
should do the trick.
The only possible advantage I can see that may have would be not having to go out to memory for a lookup table. Depending on your hardware architecture, that may or may not be a problem.
The following complete program:
#include <stdio.h>
int main (void) {
unsigned int i;
for (i = 1; i < 0x100; i = (i << 1) | 1)
printf ("%02x ", i);
putchar('\n');
return 0;
}
shows it in action:
01 03 07 0f 1f 3f 7f ff
If you only have 8 values and that's not going to change, use the array. But note that the mapping would be 0=>0x01, 1=>0x03, ... etc., because C indexing is zero-based.
Also, look for a pattern in your numbers: you could find a logic or arithmetic operation that will set the least significant N bits in a byte. I.e. N => (2 * N) -1
There is address of registry (first?) SPI1.
There is structure with offsets. I suppose it means that
SPI1_REG_BASE + offset = address of some SPI registry
#define SPI1_REG_BASE (0x01F0E000)
//-----------------------------------------------------
//Register Structure & Defines
//-----------------------------------------------------
typedef struct
{
volatile uint32_t SPIGCR0; // 0x0000
volatile uint32_t SPIGCR1; // 0x0004
volatile uint32_t SPIINT; // 0x0008
volatile uint32_t SPILVL; // 0x000C
volatile uint32_t SPIFLG; // 0x0010
volatile uint32_t SPIPC0; // 0x0014
volatile uint32_t SPIPC1; // 0x0018
volatile uint32_t SPIPC2; // 0x001C
volatile uint32_t SPIPC3; // 0x0020
volatile uint32_t SPIPC4; // 0x0024
volatile uint32_t SPIPC5; // 0x0028
volatile uint32_t RSVD0[3]; // 0x002C
volatile uint32_t SPIDAT0; // 0x0038
volatile uint32_t SPIDAT1; // 0x003C
volatile uint32_t SPIBUF; // 0x0040
volatile uint32_t SPIEMU; // 0x0044
volatile uint32_t SPIDELAY; // 0x0048
volatile uint32_t SPIDEF; // 0x004C
volatile uint32_t SPIFMT0; // 0x0050
volatile uint32_t SPIFMT1; // 0x0054
volatile uint32_t SPIFMT2; // 0x0058
volatile uint32_t SPIFMT3; // 0x005C
volatile uint32_t INTVEC0; // 0x0060
volatile uint32_t INTVEC1; // 0x0064
} spi_regs_t;
There are some definitions and the definition of pointer *spi
#define CSDEF0 (0x00000001) //bit 0
#define CSHOLD (0x10000000) //bit 28
spi_regs_t *spi = (spi_regs_t *)SPI1_REG_BASE;
I misunderstood setting of bits. For example,
spi->SPIDEF |= CSDEF0 //set 0 bit in the registry field
I understand that SPIDEF - is SPI register which has offset address 4Ch
(0x01F0E000 + 0x4C). But why CSDEF0 is bit 0 ?? There is a field CSDEF in SPIDEF registry (0-7 bits). Is it mean that 7 bit of CSDEF has address 0x00000008 ? and 5 bit has address 0x00000006?
But then why CSHOLD field of SPIDAT1 registry has address 0x10000000 ??
spi->SPIDAT1 |= CSHOLD //set bit 28
SPIDAT1 register has offset address 3Ch (0x01F0E000 + 0x3C)
It truly has field CSHOLD (28st bit)
How does |= work in this situation?
I'll be grateful for any help for figuring out... all this %)
I think you are misunderstanding the notions of address and value of the registers.
You are right (based on the structure description you gave) when you say that the CSDEF0 register of the SPI1 module is located at address 0x01F0E000 + 0x4C. This address will never change, it is defined by the hardware design.
Now with the following statements you are not manipulating addresses but values of the registers:
spi->SPIDEF |= CSDEF0; //set 0 bit in the registry field
spi->SPIDAT1 |= CSHOLD; //set bit 28
The |= operator is a bitwise OR and assign operator. It is equivalent to the following :
spi->SPIDEF = spi->SPIDEF | CSDEF0; //set 0 bit in the registry field
spi->SPIDAT1 = spi->SPIDAT1 | CSHOLD; //set bit 28
As CSDEF0 is defined to 0x00000001, in the first statement you are effectively setting the LSB bit of the SPIDEF register, leaving all other bits to their original value.
But why CSDEF0 is bit 0 ??
The purpose of this macro is to set bit-0 to 1. If this macro is ORed with any register, then that register's bit-0 is set to 1.
For example
Lets take spi->SPIDEF = 0x050A i.e 0x050A ==> 0000 0101 0000 1010
Now setting 0th bit of spi->SPIDEF using CSDEF0 .
0x050A ==> 0000 0101 0000 1010
CSDEF0 ==> 0000 0000 0000 0001
--------------------
spi->SPIDEF ==> 0000 0101 0000 1011
why CSHOLD field of SPIDAT1 registry has address 0x10000000??
Same-way how CSDEF0 is used to represent 0th bit, CSHOLD is used for 28th bit.
I guess you confused with Hexa-deciamal and binary representation of 0x000001 and 000001 (???).
0x01 is 01.
0x02 is 10.
0x100 is 1 0000 0000
0x1000 is 1 0000 0000 0000
0x10000000 is 1 0000 0000 0000 0000 0000 0000 0000
^-- Bit 28 starting from bit-0
But why CSDEF0 is bit 0 ?
Because of:
#define CSDEF0 (0x00000001) //bit 0
What they mean is not a "bit with value 0" but "the bit at position 0".
And concerning the:
#define CSHOLD (0x10000000) //bit 28
Take a look at converting hex-notation to binary-notation and it will become clear.
How does |= work in this situation?
The 1-bits AT those positions (0 and 28) are or'ed into the value that was previously in that variable.
Bits don't have individual addresses.
Instead a common practise in embedded world is to concatenate several small attributes to a larger register. e.g. one could define some internals of realtime scheduler as:
31 30 29 28 27 26 25 24 32 22 21 20 19 18 0
[ max_priority ] [ current_priority] [ reserved] [ address_xxxx ]
Here max_priority would be 5-bit unsigned integer having values 0-31;
One could as well define max_priority0 being the least significant bit of that value. All these parameters would be accessed within the same absolute address (REG_BASE + offset).