Question on working with large bit fields

Discussion about the ZBasic language including the System Library. If you're not sure where to post your message, do it here. However, do not make test posts here; that's the purpose of the Sandbox.
Post Reply
TimC
Posts: 12
Joined: 25 January 2006, 7:22 AM
Location: Boston, MA

Question on working with large bit fields

Post by TimC »

Hi all,
I am trying to work with a DS1923 which has many small bit fields and large numbers that are a series of bytes. I can read one or more bytes at a time but I must write 32 bytes back at a time.

I have tried "based" variables, Aliases, and Unions. Large numbers seem to work but not bit fields. For example having a bit field occupy the same space as a Byte did not compile.

Code: Select all

Union StatusM
	Public b as Byte
Structure myBits
	b0 as Boolean 
	b1 as Boolean 
	b2 as Boolean 
	b3 as Boolean 
	b4 as Boolean 
	b5 as Boolean 
	b6 as Boolean 
	b7 as Boolean 
End Structure
End union
Also this did not work because we are counting bytes not bits.

Code: Select all

Dim StatusM as Byte
Dim b0 as Boolean Based StatusM + 0
Dim b1 as Boolean Based StatusM + 1
Dim b2 as Boolean Based StatusM + 2
GetBit/PutBit work but it's hard to read the logic of the code. Using Constants help if you have the data sheet in front of you on which status byte contains the Mission in Progress.

Code: Select all

If ((ReadMemory(StatusM) AND MissionInProgress) > 0) THEN
    debug.print "Mission in Progress! No Alarm change should be made"
    exit sub
end if
'-----------------------------
Ideal because the MissionInProgress is tied to the status byte.

Code: Select all

If (StatusM.MissionInProgress) THEN
    debug.print "Mission in Progress! No Alarm change should be made"
    exit sub
end if
I would like to handle the problem by reading in 32 bytes to a Structure+Union. Do analysis and reporting change what is needed and write it all back. Is a large Structure+Union like this possible?

Thanks
Tim
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

The Structure myBits won't produce the result that you want because each Boolean variable consumes a full byte - they don't get packed into bytes.

Some quick experimentation with the code below suggests that it might meet your needs. The Union bar allows you to refer to a byte as a whole or an individual bit of the byte. The bit with index zero is the least significant bit of the byte and index 7 is the most significant byte. If useful, you could also add an array of two Nibble variables to the union to allow accessing the high or low four bits as a unit.

Since you mentioned 32 bytes, I defined the array d as having 32 elements. The element at index zero is the lowest addressed element.

Running this simple test produces the results that one would expect, i.e. the correct bit is getting written and read.

Code: Select all

Union bar 
  Public b as Byte
  Public ba(0 to 7) as Bit
End Union

Public d(0 to 31) as bar
Public a as bar

Sub Main()
  Call foo()
  Debug.Print "0x"; CStrHex(a.b); ", 0x"; CStrHex(d(3).b)
End Sub

Sub foo()
	a.ba(7) = 1
	d(3).ba(3) = 1
End Sub
- Don Kinzer
TimC
Posts: 12
Joined: 25 January 2006, 7:22 AM
Location: Boston, MA

Post by TimC »

Thank you for such a speedy reply!

Since every byte is different and every bit field is different joining them all together as an array of (0-31) won't work. What I was working on but feel is the wrong direction was this definition of each byte here:

Code: Select all

Public Const Clock_f41				as UnsignedInteger	= &H0200	'3 bytes
Public Const Date_f41				as UnsignedInteger	= &H0203	'3 bytes
Public Const SampleRate_f41			as UnsignedInteger	= &H0206	'2 bytes Integer
Public Const TempLowAlarm_f41		as UnsignedInteger	= &H0208
Public Const TempHighAlarm_f41		as UnsignedInteger	= &H0209
Public Const HumidityLowAlarm_f41	as UnsignedInteger	= &H020A
Public Const HumidityHighAlarm_f41	as UnsignedInteger	= &H020B
Public Const Temp_f41				as UnsignedInteger	= &H020C	'1.5 bytes
Public Const Humidity_f41			as UnsignedInteger	= &H020E	'1.5 bytes
Public Const TempAlarmControl_f41	as UnsignedInteger	= &H0210
Public Const HumidAlarmControl_f41	as UnsignedInteger	= &H0211
Public Const ClockControl_f41		as UnsignedInteger	= &H0212
Public Const MissionControl_f41		as UnsignedInteger	= &H0213
Public Const AlarmStatus_f41		as UnsignedInteger	= &H0214
Public Const GeneralStatus_f41		as UnsignedInteger	= &H0215
Public Const StartDelayLow_f41		as UnsignedInteger	= &H0216	'3 bytes Long
'Public Const StartDelayHigh_f41	as UnsignedInteger	= &H0218
Public Const MissionTimeStamp_f41	as UnsignedInteger	= &H0219	'6 bytes time+date
Public Const MissionSamples_f41		as UnsignedInteger	= &H0220	'3 bytes Long
Public Const DeviceSamples_f41		as UnsignedInteger	= &H0223	'3 bytes Long
Public Const Flavor_f41				as UnsignedInteger	= &H0226
Public Const PWControl_f41			as UnsignedInteger	= &H0227	
Public Const ReadPassword_f41		as UnsignedInteger	= &H0228	'8 bytes (2xLongs)
Public Const FullPassword_f41		as UnsignedInteger	= &H0230	'8 bytes (2xLongs)
Now within 8 of these bytes are these controls scattered across the bytes above

Code: Select all

Public Structure f41AllControls
	Public SampleRate as UnsignedInteger
	Public LowTempAlarm as Single
	Public HighTempAlarm as Single
	Public LowHumidAlarm as Single
	Public HighHumidAlarm as Single
	Public EnableTempHighAlarm as Boolean
	Public EnableTempLowAlarm as Boolean
	Public EnableHumidHighAlarm as Boolean
	Public EnableHumidLowAlarm as Boolean
	Public EnableHighSpeedSample as Boolean
	Public EnableOscillator as Boolean
	Public StartMissionOnTempAlarm as Boolean
	Public RooloverActive as Boolean
	Public HighResTemp as Boolean
	Public HighResHumid as Boolean
	Public EnableHumidLogging as Boolean
	Public EnableTempLogging as Boolean
	Public StartDelay as Long
	Public PWcontrol as Boolean
End Structure
And within 6 of those bytes are these status Bits

Code: Select all

Public Structure f41Status
	Public BatteryOnResetAlarm as Boolean
	Public TempHighAlarm as Boolean
	Public HumidHighAlarm as Boolean
	Public TempLowAlarm as Boolean
	Public HumidLowAlarm as Boolean
	Public WaitForTempAlarm as Boolean
	Public WaitForHumidAlarm as Boolean
	Public MemoryCleared as Boolean
	Public MissionInProgress as Boolean
End Structure
In addition there are informational R/O bytes such as Temperature, Humidity and Time that change quicker so are separate from Status.

The problem as I mentioned before is so much code is spent pulling the data together to make sense of it. Using GetBit and &B0010_0000 defines make the code unreadable. Can't variable names point to where the variables sit?
  • - One handle or address for the top of the 32bit array.
    - A name or address for each of the named bytes and
    - Names for all the bit data.
So going back to your solution I would need to write this type of structure for each of the bytes.

Code: Select all

Union bar ( or maybe TempAlarmControl_f41 )
  Public b as Byte
  Public ba_blank0 as bit
  Public ba_EnableTempHighAlarm as bit  'now we can address an alarm bit
  Public ba_EnableTempLowAlarm  as bit
  Public ba_EnableHumidHighAlarm  as bit
  Public ba_EnableHumidLowAlarm  as bit
  Public ba_blank5 as bit
  Public ba_blank6 as bit
  Public ba_blank7 as bit
End Union
Then for each of the 32 Unions/bytes I would need to pull them together as an array. This is not as important since there would be only 2 places in the code where all the bytes would be read and written. So I could use a list instead of a loop.

Regards
Tim
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

TimC wrote:Can't variable names point to where the variables sit?
Yes. That's what Based variables are for. However, Based sub-byte types aren't supported because in addition to the base address you'd also have to specify the intra-byte offset and there is no provision to do that.

Also, I want to remind you that the Boolean type in a structure takes up eight bits, not one as you would like. Further, the compiler will allow you to define an element of a Structure that is a Bit type, it incorrectly allocates a full byte of space in the Structure for each such element. What it should do is pack Bit and Nibble elements into one or more bytes, adding filler as necessary when an non-sub-byte type element is encountered.

I think that the best that you're going to be able to do is to read the data from the device and then unpack it into a larger structure containing Single, Boolean, etc. types, do your operations on that structure and then, if necessary, re-pack the expanded structure into the device-compatible data block.

If it is any consolation, even C/C++ don't have the ability to operate on individual bits as standalone variables so one would have to resort to the same type of drudgery with those languages.
- Don Kinzer
TimC
Posts: 12
Joined: 25 January 2006, 7:22 AM
Location: Boston, MA

Post by TimC »

Thank you this is very helpful.

You are right I am thinking boolean is one bit. It's good to know that there are limits. So it does become a constant unpack to read then pack to save back. When I'm done I will post it here

Regards
Tim
Post Reply