[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

C Structure with Bit Fields into VB.Net

Posted on 2006-04-04
14
Medium Priority
?
1,443 Views
Last Modified: 2012-06-21
Hi All,

I have been struggling with trying to convert this C Structure into VB.Net.  The problem is that it has bit fields in it.  I have tried searching online for a solution but have not been able to come up with one.  The closest I have come up with is using BitVector32.  I have tried creating a BitVector32 and then using bitvector32.sections but the fields don't seem to match up.  Am I doing something wrong?

Here is the C class:
ISISBATTERYSTATUS
This structure is used to retrieve the current status of the Q•200’s batteries. It is defined as a C structure in the following way:

    typedef struct tagISISBATTERYSTATUS
       {
           WORD Unused1:2;  /* used to be Standby battery status            */
           WORD BatChgd:1;  /* Battery changed flag                         */
           WORD BatFault:1; /* Smart battery fault detected flag            */
           WORD BatType:1;  /* Battery type 1=Smart, 0=Not smart            */
           WORD BatStat:3;  /* Smart battery status (see IBS_MAIN defines)  */
           WORD BatLife:7;  /* % remaining or 127 if unknown                */
           WORD ChrgConn:1; /* Charger connected flag                       */
           WORD CapLeft:14; /* Estimated mAh remaining (0x3FFF if unknown)  */
           WORD CapUnreliable:1;  /* CapLeft unreliable flag              */
           WORD ChrgOk:1;   /* Charging allowed if smart battery fitted     */
           WORD Unused2:4;  /* Future Use                                   */
           WORD StdByChrgAllow:1; /* Allow Stand By battery charge        */
           WORD StdByStat:3;      /* Standby battery status               */
       } ISISBATTERYSTATUS, *PISISBATTERYSTATUS;

The bit fields for ISISBATTERYSTATUS are defined as follows:
/* ISISBATTERYSTATUS bit field values   */
#define IBS_STANDBYNOTKNOWN 0x00  /* not used in Q200       00 Not Used         */
#define IBS_STANDBYCRITICAL 0x01  /*                        01 Not Used         */
#define IBS_STANDBYLOW      0x02  /*                        10 Not Used         */
#define IBS_STANDBYHIGH     0x03  /*                        11 Not Used         */
#define IBS_CHANGED         0x01  /* Main battery changed since last read       */
#define IBS_FAULT           0x01  /* Main battery fault (smart battery only)    */
#define IBS_SMART           0x01  /* Smart main battery (else alkaline)         */
#define IBS_MAINNOTKNOWN    0x00  /* Main battery ststus 000 Not Known          */
#define IBS_MAINCRITICAL    0x01  /*                     001 Critical           */
#define IBS_MAINLOW         0x02  /*                     010 Low                */
#define IBS_MAINHIGH        0x03  /*                     011 High               */
#define IBS_MAINCHARGING    0x04  /*                     100 Charging           */
#define IBS_MAINNKWAKEUP    0x05  /*                     101 Not known (wakeup) */
#define IBS_MAINCRGCOMPLETE 0x06  /*                     110 Charging completed */
#define IBS_MAINNOBATTERY   0x07  /*                     111 No Battery         */
#define IBS_STBNOTKNOWN     0x00  /* Stanby battery ststus 000 Not Known        */
#define IBS_STBCRITICAL     0x01  /*                     001 Critical           */
#define IBS_STBLOW          0x02  /*                     010 Low                */
#define IBS_STBHIGH         0x03  /*                     011 High               */
#define IBS_STBCHARGING     0x04  /*                     100 Charging           */
#define IBS_STBNKWAKEUP     0x05  /*                     101 Not known (wakeup) */
#define IBS_STBCRGCOMPLETE  0x06  /*                     110 Charging completed */
#define IBS_STBNOBATTERY    0x07  /*                     111 No Battery         */
#define IBS_STBCHARGALLOWED 0x01  /* Standby charging allowed.                  */

Here is what I have attempted with the BitVector32
    '    Public Structure ISISBatteryStatus
    Dim BatteryStatus As BitVector32
    Dim unused As BitVector32.Section
    Dim BatChgd As BitVector32.Section     '   /* Battery changed flag                         */
    Dim BatFault As BitVector32.Section    '   /* Smart battery fault detected flag            */
    Dim BatType As BitVector32.Section     '   /* Battery type 1=Smart, 0=Not smart            */
    Dim BatStat As BitVector32.Section     '   /* Smart battery status (see IBS_MAIN defines)  */
    Dim BatLife As BitVector32.Section     '   /* % remaining or 127 if unknown                */
    Dim ChrgConn As BitVector32.Section    '   /* Charger connected flag                       */
    Dim CapLeft As BitVector32.Section     '   /* Estimated mAh remaining (0x3FFF if unknown)  */
    Dim CapUnreliable As BitVector32.Section   '   /* CapLeft unreliable flag              */
    Dim ChrgOk As BitVector32.Section      '   /* Charging allowed if smart battery fitted     */
    Dim Unused2 As BitVector32.Section     '   /* Future Use                                   */
    Dim StdByChrgAllow As BitVector32.Section  '   /* Allow Stand By battery charge        */
    Dim StdByStat As BitVector32.Section   '   /* Standby battery status               */

    <DllImport("Q200api.dll")> _
    Private Shared Function psuGetBatteryStatus(ByRef pBatteryStatus As BitVector32) As Boolean
    End Function

...
sub new()
...
        BatteryStatus = New BitVector32
        unused = BitVector32.CreateSection(2)
        BatChgd = BitVector32.CreateSection(1, unused)
        BatFault = BitVector32.CreateSection(1, BatChgd)
        BatType = BitVector32.CreateSection(1, BatFault)
        BatStat = BitVector32.CreateSection(3, BatType)
        BatLife = BitVector32.CreateSection(7, BatStat)
        ChrgConn = BitVector32.CreateSection(1, BatLife)
        CapLeft = BitVector32.CreateSection(14, ChrgConn)
        CapUnreliable = BitVector32.CreateSection(1, CapLeft)
        ChrgOk = BitVector32.CreateSection(1, CapUnreliable)
        Unused2 = BitVector32.CreateSection(4, ChrgOk)
        StdByChrgAllow = BitVector32.CreateSection(1, Unused2)
        StdByStat = BitVector32.CreateSection(3, StdByChrgAllow)
...
end sub

I then call the Function and try to extract the values like this:
        psuGetBatteryStatus(BatteryStatus)

        Dim msg As String = "Battery Status:" + vbCrLf + _
        "Unused:  " + BatteryStatus(unused).ToString + vbCrLf + _
        "Battery Changed: " + BatteryStatus(BatChgd).ToString + vbCrLf + _
        "Battery Fault: " + BatteryStatus(BatFault).ToString + vbCrLf + _
        "Battery Type: " + BatteryStatus(BatType).ToString + vbCrLf + _
        "Battery Status: " + BatteryStatus(BatStat).ToString + vbCrLf + _
        "Battery Life: " + BatteryStatus(BatLife).ToString + vbCrLf + _
        "Charger Connected: " + BatteryStatus(ChrgConn).ToString + vbCrLf + _
        "Capacity Left: " + BatteryStatus(CapLeft).ToString + vbCrLf + _
        "Capacity Unreliable: " + BatteryStatus(CapUnreliable).ToString + vbCrLf + _
        "Charging Allowed: " + BatteryStatus(ChrgOk).ToString + vbCrLf + _
        "Unused 2: " + BatteryStatus(Unused2).ToString + vbCrLf + _
        "Allow Standby Bat Charge: " + BatteryStatus(StdByChrgAllow).ToString + vbCrLf + _
        "StandBy Status: " + BatteryStatus(StdByStat).ToString


Any help that you can provide would be of great assistance!

Thanks!

Don
0
Comment
Question by:dneelin
  • 7
  • 4
  • 2
  • +1
14 Comments
 
LVL 5

Expert Comment

by:xersoft
ID: 16374644
I'm not understanding possably exactly what you are asking but look into

http://msdn2.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute(VS.80).aspx
for from StructLayoutAttribute information and

Also look into the FlagsAttribute class which can be applied to an enum to make it a bit field
0
 
LVL 3

Author Comment

by:dneelin
ID: 16375054
Thanks for you quick reply Xersoft.

I am trying to emulate the C structure in VB.Net so that I can pull out the data from the structure.

I tried usint the StructLayout, but the fieldoffset class is not supported in .NetCF 1.1. I cannot upgrade to 2.0 because the OS is CE.Net 4.2.

I will try the Enum stuff after I get the correct values being populated into the Structure.

Thanks!
0
 
LVL 5

Expert Comment

by:xersoft
ID: 16375153
what does

WORD BatStat:3;  /* Smart battery status (see IBS_MAIN defines)

mean? Is a WORD 2 bytes or Four? And what values are you expecting to be stored in this variable?


I'm guessing ONE of
#define IBS_MAINNOTKNOWN    0x00  /* Main battery ststus 000 Not Known          */
#define IBS_MAINCRITICAL    0x01  /*                     001 Critical           */
#define IBS_MAINLOW         0x02  /*                     010 Low                */
#define IBS_MAINHIGH        0x03  /*                     011 High               */
#define IBS_MAINCHARGING    0x04  /*                     100 Charging           */
#define IBS_MAINNKWAKEUP    0x05  /*                     101 Not known (wakeup) */
#define IBS_MAINCRGCOMPLETE 0x06  /*                     110 Charging completed */
#define IBS_MAINNOBATTERY   0x07  /*                     111 No Battery         */


This does not look like a bit field enumeration to me, so the enum stuff might not help in this case.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 5

Expert Comment

by:xersoft
ID: 16375198
The google search I did said it's four bytes. So that maps to Integer in .net.


What happens if you try this:
    Public Structure tagISISBATTERYSTATUS
        Public Unused1 As Integer ' /* used to be Standby battery status            */
        Public BatChgd As Integer ' /* Battery changed flag                         */
        Public BatFault As Integer ' /* Smart battery fault detected flag            */
        Public BatType As Integer ' /* Battery type 1=Smart, 0=Not smart            */
        Public BatStat As Integer ' /* Smart battery status (see IBS_MAIN defines)  */
        Public BatLife As Integer ' /* % remaining or 127 if unknown                */
        Public ChrgConn As Integer ' /* Charger connected flag                       */
        Public CapLeft As Integer ' /* Estimated mAh remaining (0x3FFF if unknown)  */
        Public CapUnreliable As Integer ' /* CapLeft unreliable flag              */
        Public ChrgOk As Integer ' /* Charging allowed if smart battery fitted     */
        Public Unused2 As Integer ' /* Future Use                                   */
        Public StdByChrgAllow As Integer ' /* Allow Stand By battery charge        */
        Public StdByStat As Integer ' /* Standby battery status               */
    End Structure
0
 
LVL 5

Expert Comment

by:xersoft
ID: 16375289
I was looking at the typedef struct tagISISBATTERYSTATUS again and noticed the numbers after the members. Are these bit offsets? And if so how can there be 40 or so bits?

If this enture structure is indeed sent in 32 bits, as I'm starting to think, make sure the low and high bytes are not being flipped. I don't know much about this but I've read that sometimes the first two bytes are sent second. I'm not sure how you'd go about flipping this in your .net code.
0
 
LVL 5

Expert Comment

by:xersoft
ID: 16375474
If you can get the output of that struct as a single integer you could use combinations of this function to test various features:


    Private Function BitOn(ByVal input As Integer, ByVal Bit As Integer) As Boolean
        Dim Mask As Long = CLng(2 ^ (Bit - 1))
        Return (input And Mask) > 0
    End Function

Test that the fifth bit is 0 and the sixth and seventh bit are 1
dim value as integer = struct bits (32)
Dim Test As Boolean = (Not BitOn(value, 5) And BitOn(value, 6) And BitOn(value, 7))

Using that information you could write a series of functions that get the information you need out of the single integer.

Not really anything much different then you are doing with the BitVector32, which by the way is new to me :) But interesting
0
 
LVL 5

Expert Comment

by:xersoft
ID: 16375497
Maybe this might work better:

    Private Function BitOn(ByVal input As Integer, ByVal Bit As Integer) As Boolean
        Dim Mask As Long = CLng(2 ^ (Bit - 1))
        Return (input And Mask) > 0
    End Function
    Private Function BitOff(ByVal input As Integer, ByVal Bit As Integer) As Boolean
        Dim Mask As Long = CLng(2 ^ (Bit - 1))
        Return (input And Mask) < 1
    End Function

Dim Test As Boolean = (BitOff(value, 5) And BitOn(value, 6) And BitOn(value, 7))
0
 
LVL 3

Author Comment

by:dneelin
ID: 16375604
Hi xersoft,

The numbers at the end are C bit fields.  They are the length of the field in bits.  1 stands for one 1 (either 1 or 0) 3 is 3 bits long (0, 1,2,3) ect.  The C structure pulls the result into the fields based on the number of bits.  This is where I am having problems.

Thanks again,
0
 
LVL 5

Assisted Solution

by:xersoft
xersoft earned 600 total points
ID: 16375686
Just so I can fully understand, take this

typedef struct tagISISBATTERYSTATUS
       {
           WORD Unused1:2;  /* used to be Standby battery status            */
           WORD BatChgd:1;  /* Battery changed flag                         */
           WORD BatFault:1; /* Smart battery fault detected flag            */
           WORD BatType:1;  /* Battery type 1=Smart, 0=Not smart            */
           WORD BatStat:3;  /* Smart battery status (see IBS_MAIN defines)  */
           WORD BatLife:7;  /* % remaining or 127 if unknown                */
           WORD ChrgConn:1; /* Charger connected flag                       */
           WORD CapLeft:14; /* Estimated mAh remaining (0x3FFF if unknown)  */
           WORD CapUnreliable:1;  /* CapLeft unreliable flag              */
           WORD ChrgOk:1;   /* Charging allowed if smart battery fitted     */
           WORD Unused2:4;  /* Future Use                                   */
           WORD StdByChrgAllow:1; /* Allow Stand By battery charge        */
           WORD StdByStat:3;      /* Standby battery status               */
       } ISISBATTERYSTATUS, *PISISBATTERYSTATUS;

Unused1 is 2 bits long so bit 1 and 2

BatChgd is 1 bit long so bit 3
BatFault is 1 bit long so bit 4

and so on?

Why when I add all the numbers up do I get a number > 32?

2
1
1
1
3
7
1
14
1
1
4
1
3
___
40


Just trying to understand :)
0
 
LVL 3

Author Comment

by:dneelin
ID: 16376330
Hi again xersoft,

You and me both about the trying to understand...  I noticed that too when you pointed it out to me.  I have no idea...  I did not write the DLL, I am just trying to implement it...  

I have given up on the BitVector32 as the number is too long for it and have gone to your suggestion of BitOn/BitOff...  I have tried using longinstead, as it is longer but I am getting strange numbers coming back...

For Bits 7 to 13 (BatLife) I should be getting the binary 1100100 (100)  or 1100011 (99) (Battery is fully Charged) but I am getting 1000100 instead.  The number being returned is 6208199440752.  The pattern that is being returned by your function BitOn starts at position 17!


0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 16376375
xersoft,

Your interpretation of bit fields is correct. Your google search was what misled you. In C there are very few types that are fixed in length. The WORD type is worse still! Not only is it not standard C, it is a common method of moving away from the more fluid types into something more reliable. Unfortunately, each creator of the 'WORD' (oooh! sounds biblical :) ) has made it a different size so we can only assume that the 'WORD' in the example is 40+ bits wide.

The bitfield is one of the most difficult to port to other languages that dont have it. Is there an equivalent in VB or do we have to shift-mask-shift trick to determine the value of a number of sequential bits in a value?

Paul
0
 
LVL 11

Accepted Solution

by:
x4u earned 1400 total points
ID: 16377093
I have absolutely no expirience with VB but with some shift and mask operations it should be possible to map it to an array of 3 16-bit unsigned integers. The entire struct has a size of 6 bytes and the bitfield is 16-bit aligned. WORD is in windows (windef.h) defined as a 16 bit wide unsigned integer.

This is the bit layout of the struct when compiled with VC++:
1st 16-bit value:
Unused1 -> 0
BatChgd -> 2
BatFault -> 3
BatType -> 4
BatStat -> 5
BatLife -> 8
ChrgConn -> 15

2nd 16-bit value:
CapLeft -> 0
CapUnreliable -> 14
ChrgOk -> 15

3rd 16-bit value:
Unused2 -> 0
StdByChrgAllow -> 4
StdByStat -> 5

Maybe the following code works. I can't test it as I have no VB installed.

' Converts an unsigned integer to a long integer. (found this one in google)
Public Function UIntToLong(ByVal Value As Integer) As Long
    If Value >= 0 Then
        UIntToLong = Value
    Else
        UIntToLong = &HFFFF& - Not Value
    End If
End Function

' I don't know whether this is valid VB but given that xersoft's code works this one might work as well hopefully
Public Function ExtractBits( ByVal input As Integer, ByVal pos As Integer, ByVal len As Long ) As Long
    Dim shifted As Long = UIntToLong( input ) / CLng( 2 ^ pos )
    Dim mask As Long = ( CLng( 2 ^ len ) * 2 ) - 1
    Return ( shifted And mask )
End Function

' i.e. if structarray is your Integer array this should give the value of BatStat and CapLeft:
Dim structarray() As Integer
ReDim structarray( 0 to 2 ) As Integer
' fill in the struct data
Dim BatStat As Long = ExtractBits( structarray( 0 ),  5, 3 )
Dim CapLeft As Long = ExtractBits( structarray( 1 ),  0, 14 )
0
 
LVL 3

Author Comment

by:dneelin
ID: 16383996
Hi All,

I DID IT!!!  Everything is working fine.  I did what x4u suggested and read the 3 values being passed from the function and then perfomed the ExtractBits function he provided on them based on the location of the field as defined in the C structure.

One thing I did learn was that for the ExtractBits the len value is one less than the length of the field in the C structure.

Thanks to x4u and xersoft for your input and adding to my understanding of Bitfields and bit shifting!  You both have been a great help!
0
 
LVL 11

Expert Comment

by:x4u
ID: 16384115
Cool, great that it works. Now that you mention it, I see that the len is not treated right in ExtractBits. Here is a version that corrects this, so you can use the length as it is in the C structure. It also uses integer division for the calculation of the shifted value which might be better suited.

Public Function ExtractBits( ByVal input As Integer, ByVal pos As Integer, ByVal len As Long ) As Long
    Dim shifted As Long = UIntToLong( input ) \ CLng( 2 ^ pos )
    Dim mask As Long = CLng( 2 ^ len ) - 1
    Return ( shifted And mask )
End Function
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: jpaulino
XML Literals are a great way to handle XML files and the community doesn’t use it as much as it should.  An XML Literal is like a String (http://msdn.microsoft.com/en-us/library/system.string.aspx) Literal, only instead of starting and ending with w…
A while ago, I was working on a Windows Forms application and I needed a special label control with reflection (glass) effect to show some titles in a stylish way. I've always enjoyed working with graphics, but it's never too clever to re-invent …
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calcul…
Suggested Courses
Course of the Month17 days, 16 hours left to enroll

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question