How to set multiple bit values within an integer - vb.net

I am coding a program in vb.net using Visual Studio 2015. I am trying to figure out how to modify individual bits in a 16 bit integer. The numeric data-type byte-order is little-Indian and is as follows:
origin (2 bits)
tagged (1 bit)
addressable (1 bit)
protocol (12 bits)
Field: [ origin ] [tagged] [addressable] [protocol]
Bits: 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
In the example code below, I am trying to figure out how to set origin, tagged, addressable and protocol in the variable "i" which is a 16 bit integer.
Dim i As UInt16 = 0
Dim origin As Byte = 0 ' Message origin indicator
Dim tagged As Byte = 0 ' Determines usage of the Frame Address target field (0 or 1)
Dim addressable As Byte = 0 ' Message includes a target address (0 or 1)
Dim protocol As UInt16 = 1024 ' Protocol number: must be 1024 (decimal)
Can anyone provide a vb.net example of how I can update the variable "i" so that it contains the bit values for origin, tagged, addressable and protocol?

You can use a combination of or to set individual bits and >> and << to shift bits.
For example, to set two bytes from tagged, addressable and protocol, you can do:
Dim tagged As Byte = 1 ' Determines usage of the Frame Address target field (0 or 1)
Dim addressable As Byte = 1 ' Message includes a target address (0 or 1)
Dim protocol As UInt16 = 1026 ' Protocol number: must be 1024 (decimal)
sendbuf(0) = sendbuf(0) or tagged ' bit 0
sendbuf(0) = sendbuf(0) or (addressable << 1) ' bit 1
sendbuf(0) = sendbuf(0) or ((protocol << 2) and 255) ' first 6 bits of protocol
sendbuf(1) = sendbuf(1) or (protocol >> 6) ' next 6 bits of protocol
You may need to adjust it - I didn't follow the link, so I'm not completely sure which bits should go where (there's 14 bits to fit into 2 bytes).

Map the bit values using binary values in an enumeration. 1 = 1, 2 = 10, 4 = 100, etc. Then you can assign your variable using the enumeration. You can also combine the values into a new enumeration (see ProtocolX).
To give initial values, just add the enumeration you want to use.
' switch bits on 1, 5, 13, 14, 16
i = FrameSectionEnum.ProtocolBit1 + FrameSectionEnum.ProtocolBit5 +
FrameSectionEnum.AddressableBit13 +
FrameSectionEnum.TaggedBit14 + FrameSectionEnum.OriginBit16
PrintBits(i)
To switch on some bits and preserve the other bits, use OR.
' switch bits on 2 and 3 using a combined value. preserve other bits
i = SetOn(i, FrameSectionEnum.ProtocolX)
PrintBits(i)
To switch off some bits and preserve the other bits, use AND and NOT.
' switch bits off 1 and 5
i = SetOff(i, FrameSectionEnum.ProtocolBit1 + FrameSectionEnum.ProtocolBit5)
PrintBits(i)
List of utilities functions:
Check if certain bits is on:
Function CheckBit(i As Integer, bit As FrameSectionEnum) As Integer
Return If((i And bit) = bit, 1, 0)
End Function
Set bits on, preserve other bits:
Function SetOn(i As Integer, bit As FrameSectionEnum) As Integer
Return i Or bit
End Function
Set bits off, preserve other bits:
Function SetOff(i As Integer, bit As FrameSectionEnum) As Integer
Return i And (Not bit)
End Function
Full code:
Module Module1
Enum FrameSectionEnum
ProtocolBit1 = 1
ProtocolBit2 = 2
ProtocolBit3 = 4
ProtocolBit4 = 8
ProtocolBit5 = 16
ProtocolBit6 = 32
ProtocolBit7 = 64
ProtocolBit8 = 128
ProtocolBit9 = 256
ProtocolBit10 = 512
ProtocolBit11 = 1024
ProtocolBit12 = 2048
AddressableBit13 = 4096
TaggedBit14 = 8192
OriginBit15 = 16384
OriginBit16 = 32768
ProtocolX = ProtocolBit2 + ProtocolBit3
End Enum
Sub Main()
Dim i As UInt16 = 0
' switch bits on 1, 5, 13, 14, 16
i = FrameSectionEnum.ProtocolBit1 + FrameSectionEnum.ProtocolBit5 +
FrameSectionEnum.AddressableBit13 +
FrameSectionEnum.TaggedBit14 + FrameSectionEnum.OriginBit16
PrintBits(i)
' switch bits on 2 and 3 using a combined value. preserve other bits
i = SetOn(i, FrameSectionEnum.ProtocolX)
PrintBits(i)
' switch bits off 1 and 5
i = SetOff(i, FrameSectionEnum.ProtocolBit1 + FrameSectionEnum.ProtocolBit5)
PrintBits(i)
Console.ReadKey(True)
End Sub
Function SetOn(i As Integer, bit As FrameSectionEnum) As Integer
Return i Or bit
End Function
Function SetOff(i As Integer, bit As FrameSectionEnum) As Integer
Return i And (Not bit)
End Function
Function CheckBit(i As Integer, bit As FrameSectionEnum) As Integer
Return If((i And bit) = bit, 1, 0)
End Function
Sub PrintBits(i As Integer)
Console.Write(CheckBit(i, FrameSectionEnum.OriginBit16))
Console.Write(CheckBit(i, FrameSectionEnum.OriginBit15))
Console.Write(CheckBit(i, FrameSectionEnum.TaggedBit14))
Console.Write(CheckBit(i, FrameSectionEnum.AddressableBit13))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit12))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit11))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit10))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit9))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit8))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit7))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit6))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit5))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit4))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit3))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit2))
Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit1))
Console.WriteLine()
End Sub
End Module

The header format in the question contains the key to getting all the bits in the right place. For me personally, it's easier to visualize if you renumber the bits using a zero-based index:
Field: [ origin ] [tagged] [addressable] [protocol]
Bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Starting with the origin field, it needs to be shifted 14 bits to the left, which can be done like this:
origin << 14
The tagged and addressable fields need to be shifted to the left by 13 and 12 bits, respectively, which can be done the same way. The protocol field is already in the right place, so it doesn't need to be shifted. They can all be combined together with the Or operator as follows:
i = (origin << 14) Or (tagged << 13) Or (addressable << 12) Or protocol
One last detail that needs to be addressed is that in VB.NET, bit shift operations are dependent upon the datatype that is being shifted. In your code above, the origin, tagged, and addressable variables are all of type Byte. Shifts on this type will all be done modulo 8 (the number of bits in a byte), meaning a shift of 9 bits is the same of a shift of 1 bit.
Because all of our shifts are more than 8 bits, we need to convert to a wider datatype or else things won't end up in the right place. The easy way to do this is to just change the declarations of all the variables to UInt16:
Dim i As UInt16
Dim origin As UInt16 = 0
Dim tagged As UInt16 = 0
Dim addressable As UInt16 = 0
Dim protocol As UInt16 = 1024
i = (origin << 14) Or (tagged << 13) Or (addressable << 12) Or protocol
The alternative to this is to keep your variables declared as they are and use CType to convert the fields right before doing the shifts:
Dim i As UInt16 = 0
Dim origin As Byte = 0
Dim tagged As Byte = 0
Dim addressable As Byte = 0
Dim protocol As UInt16 = 1024
i = (CType(origin, UInt16) << 14) Or (CType(tagged, UInt16) << 13) Or (CType(addressable, UInt16) << 12) Or protocol
Personally, I prefer the first way due to brevity, but the choice is yours!

Related

Bitcoin blockchain parser c# snippet to vb

I am trying to get this snippet to vb but keep getting errors in the ide
var header = new byte[8];
int index = 0;
var magic_signature = ((uint)header[index++] << 0) | ((uint)header[index++] << 8) | ((uint)header[index++] << 16) | ((uint)header[index++] << 24);
I tried an online coverter and got this (which produces errors)
Dim magic_signature = (CUInt(header(Math.Max(Threading.Interlocked.Increment(index), index - 1))) << 0) Or (CUInt(header(Math.Max(Threading.Interlocked.Increment(index), index - 1))) << 8) Or (CUInt(header(Math.Max(Threading.Interlocked.Increment(index), index - 1))) << 16) Or (CUInt(header(Math.Max(Threading.Interlocked.Increment(index), index - 1))) << 24)
The header variable is filled after declaration.
Could someone help me convert the above to vb.net?
EDIT:
Populating header via reading a stream
Dim header = New Byte(8) {}
If stream.Read(header, 0, 8) < 8 Then
Throw New ApplicationException("Incomplete data.")
End If
As Mike_OBrien has pointed out, VB doesn't have a built-in ++ - but we can fake one easily enough:
Function PostIncr(ByRef x As Integer) As Integer
' PostIncr(i) works like i++
Dim x0 As Integer = x : x += 1 : Return x0
End Function
After that, conversion is straightforward:
Dim header(7) As Byte
' Make believe this is a stream.Read
Array.Copy({CByte(1), CByte(2), CByte(3), CByte(4)},
header, 4)
Dim index As Integer = 0
Dim magic_signature = CUInt(header(PostIncr(index))) << 0 Or
CUInt(header(PostIncr(index))) << 8 Or
CUInt(header(PostIncr(index))) << 16 Or
CUInt(header(PostIncr(index))) << 24
And for fun:
Function PreIncr(ByRef x As Integer) As Integer
' PreIncr(i) works like ++i
x += 1 : Return x
End Function
I believe David Wilson is on the right path but as rskar pointed out the Index + 1 portion does not produce the same results as index++ would in c#. The easiest way to get the behavior from c# would be to break the single command into multiple commands and store the results in temp variables, incrementing Index between each step and then evaluating the temp variables at the end. This would result in a lot more code however.
Ex:
Dim temp1 = (CUInt(header(Index)) << 0)
Index += 1
Dim temp2 = (CUInt(header(Index)) << 8)
Index += 1
Dim temp3 = (CUInt(header(Index)) << 16)
Index += 1
Dim magic_signature As UInteger = temp1 Or temp2 Or temp3 Or (CUInt(header(Index)) << 24)
Unfortunately to my knowledge there isn't anything in vb.net that behaves the same as the ++ operator in c#.

Convert Number to IP Address (v4)

I'm trying to convert a four digit number into an IP Address. For example:
0001 ---> *.192.1.01
0011 ---> *.192.11.01
0111 ---> *.192.111.01
1111 ---> *.196.87.01
3458 ---> *.205.130.01
I believe the subnet mask is 255.255.192.0.
I would greatly appreciate any suggestions on the best way to do this in vb.net.
Other info:
This is for a simple pinger program where the user inputs a four digit number (the ID of the physical site that they wish to ping.) The IP Addressing scheme is simple, the 2nd & 3rd octet are used as the site number, and the fourth octet is used as the device at the site. I didn't design this scheme, hence why I'm unsure on how to get vb.net to understand it.
What I've Tried:
I thought about doing it the following way, which is extremely crude. However this would only work up to *.192.255.01 as I don't know how to split the number between the two octets once it goes over 255 in octet 3.
Private Sub btnStartPing(sender As Object, e As EventArgs) Handles btnStartPing.Click
Dim Octet1 As Integer = *
Dim Octet2 As Integer = 192
Dim Octet3 As Integer = txtSiteID.text
Dim Octet4 As Integer = 01
Dim CompleteIP As String = ""
CompletIP = Octet1 & "." & Octet2 & "." & Octet3 & "." & Octet4
'PING CompleteIP
end sub
Solution:
Dim var1 As Integer = Fix(192 + (NumericUpDown1.Value / 256))
Dim var2 As Integer = Fix((NumericUpDown1.Value Mod 256))
MsgBox("Your IP address is: " & "10." & var1 & "." & var2 & "." & "200")
End Sub
You'll need to split the number in two. Get the first half of the bits and add them to 192 and the second half of the bits are directly used.
Dim number As Integer
number = 1
Console.WriteLine("*.{0}.{1}.01", 192 + ((number And &HFF00) >> 8), number And &HFF) ' *.192.1.01
number = 11
Console.WriteLine("*.{0}.{1}.01", 192 + ((number And &HFF00) >> 8), number And &HFF) ' *.192.11.01
number = 111
Console.WriteLine("*.{0}.{1}.01", 192 + ((number And &HFF00) >> 8), number And &HFF) ' *.192.111.01
number = 1111
Console.WriteLine("*.{0}.{1}.01", 192 + ((number And &HFF00) >> 8), number And &HFF) ' *.196.87.01
number = 3458
Console.WriteLine("*.{0}.{1}.01", 192 + ((number And &HFF00) >> 8), number And &HFF) ' *.205.130.01
Take the number and split it in two
3458 = 0x0D82
0x0D
0x82
Then add 192 to the first part
0x0D + 192 = 205
0x82 = 130
This should make it
Public Function StartPing(txtSiteId As String) As String
Dim SiteId As Integer = Integer.Parse(txtSiteId)
'backslash performs integer division (no fractionary part)
'will throw an error when SiteId results in values greater than 255
'type Byte allows only values from 0 to 255
Dim Octet2 As Byte = 192 + (SiteId \ 256)
'Mod gets rest of division
Dim Octet3 As Byte = SiteId Mod 256
Return String.Format("*.{0}.{1}.01", Octet2, Octet3)
End Function

How to generate a 26-character hex string that equals to 106 bits and ((53 Ones - 53 Zeros) in binary)

I am looking for a way to generate a hexadecimal string that equals out to 106 bits, more specifically fifty three 1's and fifty three 0's after each hex char is converted to binary and added together. I'd like to keep it as random as possible considering the parameters of the request. How would I go about keeping an eye on the construction of the string so that it equals out the way I want?
For example:
(a8c05779f8934b14ce96f8aa93) =
(1010 1000 1100 0000 0101 0111 0111 1001 1111 1000 1001 0011 0100
1011 0001 0100 1100 1110 1001 0110 1111 1000 1010 1010 1001 0011)
One option is to create a list with an equal number of 0s and 1s and then sort it with an array of random keys:
Sub Main()
' Start with a list of 53 0's and 1's
Dim bitsList = New List(Of Integer)
For i = 1 To 53
bitsList.Add(1)
bitsList.Add(0)
Next
Dim bits = bitsList.ToArray()
' Create list of random keys
Dim keys = New List(Of Integer)
Dim rand = New Random()
For i = 1 To bits.Count
keys.Add(rand.Next())
Next
' Sort bits by random keys
Array.Sort(keys.ToArray(), bits)
' Create hex string
Dim s = ""
For i = 1 To bits.Length - 4 Step 4
Dim digit = bits(i + 3) * 8 + bits(i + 2) * 4 + bits(i + 1) * 2 + bits(i)
s = s + Hex(digit)
Next
Console.WriteLine(s)
End Sub
You can place 52 ones randomly in a 104 bit number by keeping track of how many ones has been placed already and calculate the probability that the next digit should be one. The first digit always has 1/2 probability (52/104), then the second digit has 51/103 or 52/103 probability depending on what the first digit was, and so on.
Put the bits in a buffer, and when it is full (four bits), that makes a hexadecimal digit that you can add to the string:
Dim rnd As New Random()
Dim bin As New StringBuilder()
Dim buf As Integer = 0, bufLen As Integer = 0, left As Integer = 52
For i As Integer = 104 To 1 Step -1
buf <<= 1
If rnd.Next(i) < left Then
buf += 1
left -= 1
End If
bufLen += 1
If bufLen = 4 Then
bin.Append("0123456789abcdef"(buf))
bufLen = 0
buf = 0
End If
Next
Dim b As String = bin.ToString()
To make a 106 bit value, change these lines:
Dim buf As Integer = 0, bufLen As Integer = 0, left As Integer = 53
For i As Integer = 106 To 1 Step -1
The resulting string is still 26 characters, the two extra bits are in the buf variable. It has a value between 0 and 3 that you can use to create the 27th character, however that is done.
To add a 22 bit hash to the string, you can use code like this:
bin.Append("048c"(buf))
Dim b As String = bin.ToString()
Dim m As New System.Security.Cryptography.SHA1Managed
Dim hash As Byte() = m.ComputeHash(Encoding.UTF8.GetBytes(b))
'replace first two bits in hash with bits from buf
hash(0) = CByte(hash(0) And &H3F Or (buf * 64))
'append 24 bits from hash
b = b.Substring(0, 26) + BitConverter.ToString(hash, 0, 3).Replace("-", String.Empty)

Generate random string in text field

We have that old software (made by one of the first employees many years ago) in company that uses Microsoft Access to run. Boss asked me to add a random string generation in the specific text box on click but i have no idea how to do that. I dont have any Microsoft Access programming experience, thats why i am askin you to help.
I managed to create button and text field so far. Thats where it stops. I also managed to access the code for the button action:
Private Sub command133_Click()
End Sub
This is one way, will work in Access VBA (which is an older basic than vb.net). It will generate a string with letters and numbers.
Sub test()
Dim s As String * 8 'fixed length string with 8 characters
Dim n As Integer
Dim ch As Integer 'the character
For n = 1 To Len(s) 'don't hardcode the length twice
Do
ch = Rnd() * 127 'This could be more efficient.
'48 is '0', 57 is '9', 65 is 'A', 90 is 'Z', 97 is 'a', 122 is 'z'.
Loop While ch < 48 Or ch > 57 And ch < 65 Or ch > 90 And ch < 97 Or ch > 122
Mid(s, n, 1) = Chr(ch) 'bit more efficient than concatenation
Next
Debug.Print s
End Sub
Try this function:
Public Function GetRandomString(ByVal iLength As Integer) As String
Dim sResult As String = ""
Dim rdm As New Random()
For i As Integer = 1 To iLength
sResult &= ChrW(rdm.Next(32, 126))
Next
Return sResult
End Function
Workin on #Bathsheba code, I did this. It will generate a random string with the number of characters you'd like.
Code :
Public Function GenerateUniqueSequence(numberOfCharacters As Integer) As String
Dim random As String ' * 8 'fixed length string with 8 characters
Dim j As Integer
Dim ch As Integer ' each character
random = ""
For j = 1 To numberOfCharacters
random = random & GenerateRandomAlphaNumericCharacter
Next
GenerateUniqueSequence = random
End Function
Public Function GenerateRandomAlphaNumericCharacter() As String
'Numbers : 48 is '0', 57 is '9'
'LETTERS : 65 is 'A', 90 is 'Z'
'letters : 97 is 'a', 122 is 'z'
GenerateRandomAlphaNumericCharacter = ""
Dim i As Integer
Randomize
i = (Rnd() * 2) + 1 'One chance out of 3 to choose one of 3 catégories
Randomize
Select Case i
Case 1 'Numbers
GenerateRandomAlphaNumericCharacter = Chr(Rnd() * 9 + 48)
Case 2 'LETTERS
GenerateRandomAlphaNumericCharacter = Chr(Rnd() * 25 + 65)
Case 3 'letters
GenerateRandomAlphaNumericCharacter = Chr(Rnd() * 25 + 97)
End Select
End Function
I use it with random number of characters, like this :
'Generates random Session ID between 15 and 30 alphanumeric characters
SessionID = GenerateUniqueSequence(Rnd * 15 + 15)
Result :
s8a8qWOmoDvC4jKRjPr5hOY12u 26
TB24qZ4cNfr6EdyY0J 18
6LZRQ9P5WHLNd71LIdqJ 20
KPN0RmlhhJKnVzPTkW 18
R2pNOKWJMKl9KpSoIV2egUNTEb1QC2 30
X8jHuupP6SvEI8Dt2wJi 20
NOTE: This is still not completely random. It will give a higher count of numbers than normal as approx 1/3 of all chars generated will be numbers.
Normally distribution will look like:
10 numbers plus 26 lowercase plus 26 uppercase = 62 possible chars.
Numbers will normally be 10/62 parts of the string or 1/6.2
With the code
i = (Rnd() * 2) + 1 'One chance out of 3 to choose one of 3 catégories
the count of numbers is pushed up to 1/3 (on average)
Probably not too much of a worry - unless you are trying to beat the NSA and then you have decreased your range significantly.

What does (iRed = Icolor Mod 256) mean?

i was studying some projects and i started The ColorPicker Project. i could not understand the LongToRgb Function >>> which as follow :
**
Private Function LongToRGB(lColor As Long) As String
Dim iRed As Long, iGreen As Long, iBlue As Long
iRed = lColor Mod 256
iGreen = ((lColor And &HFF00) / 256&) Mod 256&
iBlue = (lColor And &HFF0000) / 65536
LongToRGB = Format$(iRed, "000") & ", " & Format$(iGreen, "000") & ", " & Format$(iBlue, "000")
End Function
**
i want someone to explain to me in plain English ...
Mod is the modulo operation, which is ofter referred as % too.
It takes the remainder of the integer division between the two values. In your situation it's useful to get the meaningful part of component color (red, green, blue) from a long that contains all of them packed.
Eg:
1234 Mod 100 = 34
Mod Operator (% in C#)
Basically, it returns the remainder of a division operation. For example, 13 Mod 4 = 1, because 13 / 4 = 3 w/ a remainder of 1. It's important to understand how the long value is created to understand why the function does what it does.
All the colors (Red, Green, Blue) are represented in the amounts of 0-255. For example, imagine the following value: R(8), G(3), B(1).
To understand why the function does what it does, let's look at a scenario where number values range from 0-9 (10 values) instead of 0-255 (256 values). How would you represent a single value that you can reverse engineer the values from? You can not simply add the values together (8 + 3 + 1 = 12) because it would be impossible to reverse engineer the original values. Instead, you must multiply values by the base. The base depends on the value range... in the example it is 10 because there are 10 values. The position is a zero-based index. Red's position is 0, Green's position is 1, Blue's position is 2.
Value * (Base^Position))
Red(8) = (8 * 10^0) = 8 * 1 = 8
Green(3) = (3 * 10^1) = 3 * 10 = 30
Blue(1) = (1 * 10^2) = 1 * 100 = 100
8 + 30 + 100 = 138. And 138 can easily be reverse engineered (in fact, just by looking at it!). Mathematically reverse engineering it is done as so:
(CombinedValue / (Base^Position)) % Base = OriginalValue.
(138 / (10^0)) % 10 = (138 / 1) % 10 = 138 % 10 = 8 (Red)
(138 / (10^1)) % 10 = (138 / 10) % 10 = 13 (decimal is truncated) % 10 = 3 (Green)
(138 / (10^2)) % 10 = (138 / 100) %10 = 1 (decimal is truncated) % 10 = 1 (Blue)
The function does a few things:
It uselessly does a bitwise operator (lColor And &HFF00) and (lColor And &HFF0000) for some reason.
It simplifies the mathematics. There is no point in dividing by 1 for red (256^0 = 1), and there is no point to using the modulo operator to retrieve Green because X % 256 = X for all X where X < 256. Also, 256^2 is equal to 65536.
It uses the actual range that color values can be represented (0-255, 256 values).
You can actually use a simplified version of the function instead:
Private Function LongToRGB(lColor As Long) As String
Dim iRed As Long, iGreen As Long, iBlue As Long
iRed = lColor Mod 256
iGreen = (lColor / 256) Mod 256
iBlue = lColor / 65536
LongToRGB = Format$(iRed, "000") & ", " & Format$(iGreen, "000") & ", " & Format$(iBlue, "000")
End Function
Note that the last method is simply a string formatting function and has nothing to do with the mathematics.