Reputation: 153
Probably the worst embarrassment of the year...a comment do you understand how binary operators work?
was right.
A >> 2 #shifts the value of A to right by 2 bits
And all this time, for years, I thought 2 is shifted by the value of A in the case above!!
Sorry guys for this silly question and thank you for correcting my idiocy and your tolerance and kindness are much appreciated.
I'm trying to understand how a portion of a DIY keyboard firmware works.The firmware is called qmk: https://github.com/qmk/qmk_firmware
I'm not exactly certain but the code is in a c variant called AVR c.
The C macro changes keyboard layer when held, like a function key does, and send a hid usage id to pc when quickly tapped.
The initial value for layer is a decimal between 1 to 32.
kc is any one of the hid usage ids.
#define QK_LAYER_TAP = 0x4000
#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))
#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key))
#define ACTION_LAYER_TAP(layer, key) (ACT_LAYER_TAP<<12 | (layer)<<8 | (key))
In another file within a loop, the below is fired when user presses a key to which maybe LT(2,KC_A)
is bound.
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
break;
So, in the case of LT(2,KC_A)
, this macro #define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))
yields 04 | 0x4000 | ((2 & 0xf) << 8)
.
KC_A -> 101
0x8 -> 00001000
0xf -> 00001111
0x4000->100000000000000
2&0xf -> 00000010
((2&0xf)<<8) -> 1000000000
The firmware detects 0x4000 bit mask and calls the above case QK_LAYER_TAP
, then some magic number keycode appears which originates from LT macro.
For LT(2,04)
keycode yields 2 for (keycode >> 0x8) & 0xF
, and keycode yields 4 for keycode & 0xff
.
keycode contains a bit sequence in int16 from the first and the second parameters of the LT macro call.
Since evaluating the expression keycode & 0xff
yields the hid usage id passed to LT, it is clear keycode contains the second parameter of LT in the first 8 bits.
To this point everything is clear. But....
(keycode >> 0x8) & 0xF
yields the first parameter of TL.
00001000
4 >> 0x8
results in zero...some negative value >> 0x8
and that can be done, but I cannot wrap my head around how I can manipulate the value of (keycode >> 0x8) & 0xF
without touching the lower 8bits.Upvotes: 0
Views: 1063
Reputation: 229
As others have said, you should rewrite this as a single succinct question. ..But, it sounds like what you meant to ask is: "what is this code doing". I'll try to explain.
your case statement is executing this line: action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
ACTION_LAYER_TAP_KEY
takes 2 arguments. Lets look at them individually.
The first is (keycode >> 0x8) & 0xF
, what this does is take the keycode
and bit shift it 8 places to the right (bits that go off the end are lost). The result is then and-ed (bitwise) with 0xF
(00001111
). This has the effect of discarding everything but but the first 4 bits.
The second is keycode & 0xFF
. What this does is discard everything except the first 8 bits of keycode. So now the arguments are keycode bits 8-11 and keycode bits 0-7.
Ok, now what does ACTION_LAYER_TAP_KEY
do with this data?
#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key))
Ok, it calls ACTION_LAYER_TAP
with the same arguments. Now lets look at that.
ACTION_LAYER_TAP(layer, key) (ACT_LAYER_TAP<<12 | (layer)<<8 | (key))
First it takes ACT_LAYER_TAP
, which is probably a constant and bit shifts it by 12 to the left. Then it does the same to layer
except by 8, then it takes these two and key
and or's them (bitwise). The result will be <ACT_LAYER_TAP><layer><key>
packed into the integer. Layer can have values 0-15, and key can have values 0-255.
Refering back to the above, we can see that <layer>
is really just bits 8-11 of keycode. and key is bits 0-7 of keycode. So what we really end up with is <ACT_LAYER_TAP><first 12 bits of keycode>
packed into an integer.
Upvotes: 1
Reputation: 1485
You are dealing with firmware which is driving hardware. Shifting some bits and ORing them with others is creating the contents of a hardware register, in this case apparently a hardware configuration register.
It needs to put in bit flags, shift values, etc., to match the format of the register, which contains a lot of information, each piece one or more bits long, at specific locations.
To understand exactly what this is doing you would need to know specifics about the hw/sw interface, which may not be forthcoming.
Now, to your specific question. You wrote:
shift the above to right by 4
4 >> 0x8
results in zero...
This is shifting keycode 8 bits to the right, not shifting 8 by keycode bits. Since the first 8 bits are one value, which you have explained, this is extracting what is coded into the higher bits.
For example:
If your two parameters are 5 (to be encoded into the high part) and 4 (to be encoded into the low word):
lower word, in binary 00000100
higher word, in binary 00000101
Together: 0000010100000100
So bitwise & with 0xFF will give you 4 Shifting the value 8 bits to the right will give you 5.
Also, these are most likely unsigned integers. Signed integers are not generally used for this kind of work.
Upvotes: 1