Bitwise Operation Help
the8thst
Posts: 470
I am writing a module for an Integra Tun-3.7 and I have a question about how to process one of the responses.
The response is !6 HTS 01 01 03 $1A (the spaces were added to seperate the chunks of data)
I am fine seperating out the first chunk [01] = HD or Not HD
I am fine with the second chunk [01] = current HD stream
Its the third that I need help with [03] = available HD streams. There are 8 possible streams and 03 is a hex representation of an 8-bit binary number where each bit is 1 or 0 representing the available streams.
In the example it is [03] = 11000000 which equates to Streams 1 and 2 are available, but 3-8 are not.
I want to then turn on feedback on the touch screen for the streams that are available and put the available streams into an array so I can toggle through the available streams.
Thanks for any help you can give.
The response is !6 HTS 01 01 03 $1A (the spaces were added to seperate the chunks of data)
I am fine seperating out the first chunk [01] = HD or Not HD
I am fine with the second chunk [01] = current HD stream
Its the third that I need help with [03] = available HD streams. There are 8 possible streams and 03 is a hex representation of an 8-bit binary number where each bit is 1 or 0 representing the available streams.
In the example it is [03] = 11000000 which equates to Streams 1 and 2 are available, but 3-8 are not.
I want to then turn on feedback on the touch screen for the streams that are available and put the available streams into an array so I can toggle through the available streams.
Thanks for any help you can give.
0
Comments
$03 should read 00000011.
if sMyChar = $03 (or whatever hex code you get)
one way would be to individually check each channel for a one or zero
sMyChar BAND $01 (00000001) will return an $01 if there is a stream present and $00 if there's none
sMyChar BAND $02 (00000010) will return an $02 if there is a stream present and $00 if there's none
sMyChar BAND $04 (00000100) will return an $04 if there is a stream present and $00 if there's none
same for $08 (00001000)
same for $10 (00010000)
and so on.
There may be a better way, that's the first one that came to mind.
First write a function that gets passed an integer n and finds 2^n. This is a pretty easy task, you could even do it recursively if you want.
Then go through a loop for(i=0;i<8;i++). This will run the loop 8 times, one for each bit.
If ( 2^i & Chunk3 ) then you know stream (i+1) is available. How? Because you compared the bits of the two numbers using the bitwise AND (&).
00000011 = 3
00000001 = 1 = 2^0
00000001 = 3&1 ... Stream 1 is available
00000011 = 3
00000010 = 2 = 2^1
00000010 = 3&2 ... Stream 2 is available.
00000011 = 3
00000100 = 4 = 2^2
00000000 = 3&4 .... Stream 3 is not available. (because the two numbers had no bits in common)
and so on.
And thanks, I never liked working with binary, and thus far have been able to stay away from it. Now, even I might not be afraid to tackle it!
Are you trying to imply that if I can figure it out it must not be too hard?
If you're scared of binary then pray you never have to parse feedback from a Krell.
Well, the only time I might encounter a Krell is if I'm doing a job for someone else. But thanks for the heads up, I'll be sure that we don't sell any!
Here is a one line function that given a number and a bit position will return the value of the bit. The least most significant bit is bit 0.
You will have to explain that one Joe, as I don't follow but would like to understand. Why is the bit argument a char?
Not sure what you mean by "least most significant bit". Is that a typo?
Thanks,
Paul
This is the bit that I don't get.
Thanks for all the quick replies.
char is a 8-bit numeric datatype, which is smaller than the 16-bit integer. It can represent values 0-255, which is enough to tell which bit you want out of a 16-bit integer. Also called a byte, short, or uint8 in other programming languages.
Typo, he meant least significant bit.
Also, you can simplify the test to "number & (1<<bit) != 0" since it doesn't matter what value it has as long as it isn't zero.
<< is the left-shift operator. 1<<0 = $01 (b00000001). 1<<1 = $02 (b00000010). 1<<7 = $80 (b10000000) The expression (1<<bit) lets you easily mask out the single bit you're interested in.
Thanks for the explanation. It looked a little odd to me for a couple of reasons, one of which you mentioned (!= 0). The other is that the precedence of & is weaker than != so number will be anded with the result of (1<<bit) != 0 (which will always be 1) rather than having (number & (1<<bit)) compared against 0. Is this not the case? It is in C++ but I don't have a master to test against.
It may need mentioning to anyone using this function that the value of 'bit' starts at 0 not 1, as in the zeroth bit. So for it to return true for the number 1, bit would have to have a value of 0. I would use an int rather than a char for the argument just for clarity.
Paul
Correct. I mentioned that in my original post and AMXJeff reiterated it. Starting with 0 instead of 1 is the mathematically correct way to do it.
It?s not returning true or false for a number. The function returns the value of a bit of the number passed in. If you pass in any odd number with bit 0 then the function will always return 1 (TRUE) since b0 is always set for an odd number.
Curious as to why you feel increasing the memory space of the bit parameter to an INT adds clarity. The only ?legal? values for bit are 0-15 since the integer number passed in is 16 bits wide. But as with many things in the programming world, to each their own. An INT will work just as well as a CHAR. You can also use an INT for the RETURN instead of a CHAR. The data types of the function best suited my needs at at the time.
Yes, that?s not the case. If you test it, you will find the function works exactly as expected and intended.
You?re a very punny guy. (Where did I hear that before?)
That puzzles me. I tested it with a C++ compiler and it doesn't work correctly without the added parentheses and the operator precedence in Netlinx is the same as C++. I don't have a master to try it out on though to confirm until Monday.
Using 9 as the number and 1 as the bit with this code:
The result is 1 which is wrong. However, it is right if (1<<bit) == 1<<bit gets evaluated first since that would be 1, and then 9 anded with 1 is of course 1.
Using 9 as the number and 1 as the bit with this code
The result is 0 which is correct, since (number & (1<<bit)) gets evaluated first which is 0, and then 0 compared with 1 will return 0.
I don't understand why it would work with Netlinx code and not C when the operator precedence is the same but I will figure it out Monday I guess.
Yes it is just a quirk of mine to use an int if you are returning an int value (1 or 0 as you mentioned) and to use a char if you are returning an ascii character. Obviously you can interchange them, but I will generally always sacrifice memory (especially if its only one byte like in this case) for clarity. For instance I will never write:
even though it saves me three bytes as opposed to:
Paul
?produces the following output when button 1 is pushed:
Paul
RETURN number & (1<<bit) != 0
Extra parens never hurt anything... if you're worried about it, just write (number & (1<<bit)) != 0 to ensure it evaluates the way you intended it.
This does shock me. It's not that I am worried about it or being pedantic (not saying you are saying that) but if something as basic as operator precedence can't be relied upon it is a concern. Since Netlinx operator precedence is the same as most other languages I assume its a bug and not a mistake in the docs.
Paul
There was a time in my early programming days that I went out of my way to write terse, ultra-tight code, and relied heavily on precedence rules to minimize the source footprint. But I've long since decided that it's just not worth it in this day of large memory pools.
I couldn't agree more, but that is no excuse for the compiler to compile code incorrectly. You have to be able to rely on the compiler to do what the docs say and not behave in an undefined way. Using parentheses is supposed to be for making the code more readable to humans, not for forcing the compiler to do what the docs say it should do, especially about something so basic as operator precedence.
Paul
You are right, of course. I just thought that a good opening to share that particular viewpoint. I suppose it was a left-handed way of saying I never saw that particular bug because of my "readability" habit.
I'm just adding to this post since I found it and it helped me sort out what I wanted. In my case I wanted to create an array of the bits in a byte and the code posted above will just let you know if a particular bit is set.
These are the variations I came up with:
For testing I just drop these else if's in my code and set the var values in debug which is why they're local var except for the nRunTest which is a global
And while this thread is resurrected, an AMX library posted by David Vine on GitHub:
https://github.com/AMXAUNZ/amx-util-library
Contains some functions for converting between "typical" data and ASCII strings containing binary representations of the data values. There's more in the library, but it's unfinished.
Could be worth to have a look.