HOME  →  Delphi Tutorials TOC  →  MicroLan/ 1-Wire Tutorials TOC     Other material for programmers
Delicious.Com Bookmark this on Delicious     StumbleUpon.Com Recommend to StumbleUpon

Maxim/ Dallas 1-Wire Chips, TMEX, MicroLan

A new introduction: Written January 2014

This page has good information, and a search button at the bottom of the page
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!

Click here if you want to know more about the source and format of these pages.

This page is "browser friendly". Make your browser window as wide as you want it. The text will flow nicely for you. It is easier to read in a narrow window. With most browsers, pressing plus, minus or zero while the control key (ctrl) is held down will change the texts size. (Enlarge, reduce, restore to default, respectively.) (This is more fully explained, and there's another tip, at my Power Browsing page.)




Introduction to Delphi Programming for the Dallas 1-Wire Chips

I've been writing programs and tutorials about writing programs for the Dallas (Maxim) 1-Wire chip family for many years.

At Christmas 2013, I started a major re-write of my biggest 1-Wire program, and along the way to that, I wrote this for you, a new attempt to explain "everything you need to know" to write programs to interact with the wonderful 1-Wire chip family.

In this tutorial, you will "only" find "How To Read a 1-Wire Temperature Chip".... but master that, and you have broken the back of getting into 1-Wire programming. If you can read a temperature sensor, you can read a PIO chip, a DIO chip, a battery monitor chip (has a neat ADC, among other things), a counter chip... if you can find one. Dallas, in their wisdom, no longer manufacture this splendid and useful device.

Why ANOTHER "How to read temperature sensor" tutorial?

Did you ever get something exactly right on the first attempt? No, neither did I. Some of my 1-Wire tutorials go back to before 2006. Some are pretty "raw"! Mostly right, in the things they say, some of my early 1-Wire programs were hardly models of clarity and good design.

What is presented here is far from perfect... but it will, I hope, help you "get going" if you, too, want to do things with 1-Wire chips. This page is all about writing programs for interacting with 1-Wire chips on MicroLans. The page is written from the point of view of a Delphi programmer, but many of the points I make will guide you even if you work in a different language.

This page is far from perfect, I know. But the time I have for these things is limited. I hope the "gems" of knowledge which you can find in what follows will be adequate reward for whatever effort you have to expend.

One bit of major good news, I think: You candownload a .zip file with the program in its final state, and the sourcecode. I hope you will still read through the tutorial, as the journey to the final state is, I think, instructive.

However, I hope the following, which can be downloaded as part of the zip file DS048.zip with all the files you need to compile this project will be useful to you in seeing HOW 1-Wire work is done. Sometimes, when "stuff" is "wrapped" in units, it becomes less easy to analyze?

There is a lot of detail in this page. 1-Wire work does require some attention to detail. But few of the details are particulary arcane. Just trudge through it all, one step at a time.

Here we go...

I am a hobbyist, a retired teacher of computer programming. I've "played" with Dallas 1-Wire for many years. I have a number of programs which work.

Which isn't to say I fully understand it.

In this essay I am going to try... not for the first time... to give you an idea of my idea of "how it works". Don't take it as "gospel". Do go to the data sheets and try to forge your own understanding. But maybe what follows will help.

Before you go further with this essay, get yourself a working 1-Wire set up consisting of...

HARDWARE...

A PC... probably a Windows PC.

An "adapter". This is a bit of electronics which plugs into your computer on one side, and connects to your "MicroLan" (I'll explain in a moment) on the other.

A MicroLan (I'll explain in a moment) with at least two 1-Wire chips on it. Other things "will do", but I'm going to proceed as if your two chips are both temperature sensing chips.

SOFTWARE...

The Dallas-supplied, free, basic utility "OneWireViewer"

================ With that hardware and software, once you have all the setting up done, you should be able to...

a) Find out the unique "ID" numbers inside your 1-Wire chips. (16 character strings consisting of digits or letters from a-f, or a mixture of the two)

b) "Ask" the temperature sensing chips what temperatures they are "seeing"

(The setting up is explained at the Dallas site, on other pages on the internet written by me, and on other pages on the internet written by others.)

Once you ARE able to do those things, THEN you are ready for the part of this essay which follows the answer to "What is a MicroLan" which comes next.

============== What is a MicroLan?

I promised a little way back to say what a MicroLan is.

Yes: The "LAN" part of that is supposed to imply a "network" of sorts.

Physically, despite the trademark "1-Wire", the "backbone" of a MicroLan is TWO wires. Imagine these wires as the long pieces of a ladder, the stringers, the two pieces which join to the ends of each of the ladder's rungs. (Also known as rails or stiles.)

The wires can be long... I've had MicroLans of 40 meters, and read that even longer ones are possible.

The "rungs" are the individual 1-Wire chips. The minimum number of connections to a 1-Wire chip is two... one for each of the two wires which I have described as "the ladder's stringers".

The "ladder" in our simple, for discussion, example has just two "rungs"... a rather short ladder. (Or maybe a long ladder, with huge gaps between the rungs!)

Many 1-Wire chips have additional connections you can make to them.

The common temperature sensing chips, for instance, have one more connection. You can connect 5v to the chip via this third pin, and it is a good idea. If getting 5v to the chip would be difficult, there is an alternative "answer" called "powering the chip parasitically"... but I recommend that you postpone exploring that option as long as you can. The hassles of supplying 5v on that third pin are small to the hassles which can arise for neophytes who try to use the parasitic option.

============== So... having "caught your rabbit"... what next?

A little while back, I tried to suggest that you need to get a PC + Adapter + MicroLan with, say, two temperature sensing chips on it "playing together nicely" before this essay will be much use to you.

Here goes the material which will, I hope, enrich your understanding of what your setup can do, how you make it do things....

==== As I said... I am not "an expert", but this is the way I think about the whole system when I try to write my own programs to interact with the MicroLan.

I work in Delphi, by the way. But what I am going to say should be more than enough to get you started with 1-Wire work, whatever language (or operating system) you are using... as long as you have a system "big" enough to run the Dallas-supplied "OneWireViewer", as mentioned above.

By the way: You can access 1-Wire chips far more simply, if you make some compromises. Compromises which really don't much matter in some contexts. The Arduino, and, I suspect, Pi, communities use 1-Wire chips very happily, at the "simpler" level of which I am thinking. Visit their forums for help with their "answer".

But back to using 1-Wire chips, on MicroLans, to the max.

==== You will "talk" to the adapter... and through the adapter to the chips on the MicroLan... with "the TMEX API"

First, there is the interface between your software and the TMEX software.

In what follows, I will frequently say "You call TMxxx", where "xxx" has a variety of values, e.g. TMExtendedStartSession, TMStrongAccess.

This will work if your system has the right software modules on it, which it should, if you set up the Dallas SDK correctly... which you probably did if you've got the OneWireViewer working.

For Delphi programming, the way you give your compeller what it needs is to make iBTMEXPW.dcu available, and to put "iBTMEXPW " in the program sourcecode's "Uses" clause. I believe that this would be called "including a library" in many other languages.

So.... and I'll talk first in broad, general terms, and then go back, and say it again with some "details" filled in....

So... first you need to understand about "connecting" to the routines which Dallas has provided to you.

You "connect" by calling the TMExtendedStartSession function. You might think of it as "getting a dial tone" in terms of old fashioned "wired" telephony. (Don't be worried by the "Extended" in the name, TMExtendedStartSession. It is just an improved TMStartSession, which no one uses any more.)

It returns a number. If the number is 0 or negative, it signifies a problem. (We'll get into dealing with those cases eventually, perhaps. For now, we'll assume an number greater than zero.) The returned number (if greater than zero) is called your "session_handle". We'll be using it quite a lot in what follows.

Eventually, you should call TMEndSession. Along the way, from time to time, you may want to call TMValidSession to see if your session is still valid, still "connected"

It is via the "session" that you do everything else that you do with the 1-Wire chips on the MicroLan.

====

"Okay... I 'get' the 'session' idea", you say. "What's this about "talking" to the chips?"

I am going to explain a fairly pedestrian "answer" to that here. There are more "clever" answers, and things you may read elsewhere may be pursuing one of those, so watch out for them, lest you be confused. (And the Arduino crowd often use a simpler, but limited "answer".)

For my example, I am going to have a MicroLan with two 1-Wire temperature (tture) sensing chips on it.

Once you have established your "session", here's what you do next...

First, you send a message out on the MicroLan which resets all of the chips on it. This is to "clear the slate", to "wake up" any chips which are "asleep" (see below), and to generally get yourself to a good starting point.

Next, you send a message out on the MicroLan for every chip on the MicroLan EXCEPT the one you want to talk to! The message is "Go To Sleep (unless you are the chip I want to talk to". You tell "everyone" who it is who is you want to talk to by sending that chip's unique ID along with the command. You will, I hope, have made a note of the chip IDs earlier when you were using OneWireViewer to access the chips on the MicroLan.

Once you have told all the chips, except your one true love, to go to sleep, any further commands (except a "reset") are ignored by all the other chips, even though they are connected to the wire those commands pass through.

Using the temperature sensing chips is a two stage process. You go through all of the "Establish Session, Reset Chips, Put All But One To Sleep" stuff TWICE. (You can, as I did for many years, and as I describe in other tutorials, "wrap" the two parts up inside one "Establish Session... etc..." "package"... but it leads to unnecessary complexity. It was on the first of January, 2014, that I finally saw the light!...

You access the chip once and send a "Take Temperature" command ("Convert Temperature, code $44).

Then you back out, end the session, etc, before going back in, just as you would to do something, anything else, to the same chip or another on the MicroLan, and ask the chip to tell you what is in a block of memory inside it. If all went well in response to your earlier "Convert Tture", then there will be numbers in that buffer which tell you what the tture was when the "Convert" command was executed.

It is easy to get confused! So I will recap....

There is a "framework". You use the framework to do anything with any of the various 1-Wire chips. You do many of the same things every time you access a 1-Wire chip. There's just a little "payload" at the heart of "the framework" where you do different things depending on what you want to accomplish.

The other "trick" to getting going with all of this: To read the temperature of one of your 1-Wire tture sensors is a two step process. First you "talk" to it, just as you would any other 1-Wire chip for any other purpose, and at the heart of "the framework", you say "take a tture reading".

Shortly later, you access the chip a second time, going through all that you went through previously, and this time, at the heart of the framework, you say "tell me the numbers in your scratchpad."

In this very simple demonstration program, we are going to use two buttons to trigger the two halves of the tture reading process. It is up to the human to remember that he/ she must click the "DoTture Pt1" button before clicking the "DoTture Pt2" button.

So... onward...

The outer layer of "the framework" takes care of opening a "session". This is a connection between the code that you have written, and the resources available to you in the TMEX API.

In theory, in some situations, you can leave the session open, do more than one thing while it is open... in some circumstances.

I prefer to work in a more pedestrian manner... always fully exiting the TMEX API (with a call of the TMEndSession function) after just one iteration of "reset chips/ do something with one of the chips". I do it all, from the initial TMExtendedStartSession, each time. Just simpler. Suits this bear's not very large brain.

Ha! So much for broad theory.

I will now show you a Delphi program to do all of the above when you...

The program is NOT written to be a Good Program. It is written to help you see What Is Going On.

One feature to notice...

There is a variable called boErrL.

The whole business of trying to read a chip on the MicroLan can fail at various stages.

In this crude "What Is Going On" version of using a MicroLan, the software just gives up, for this pass, anyway, if it stumbles at any point.

This "giving up" is moderated by bErrL. If it is zero, we know that no problem has been encountered yet. At any point where a problem is detected, bErrL is set to something other than zero, and that tells subsequent phases of the process "don't bother". If you manage to use a different number at each place where you change bErrL from what it was previously, you can tell what the problem was when you exit the process. (By looking at the value in bErrL.)

This nice simple "forget the rest if an error is encountered" scheme is fine, but for one thing.

You have to provide for the following: Imagine that you have successfully opened a session, started to "do things", and THEN encounter an error. You don't do much else, but you DO do an "EndSession" on your way out of "the framework". This is tedious, but providing for it is not terribly difficult.

PHASE ONE VERSION....
procedure TDS048f1.ReadChip;
//This is a rough outline, to show the "shape" of the ReadChip routine
//Some of the "routines" called are not yet written.
var bErrL:byte;
begin
showmessage('to be finished');
//This is a rough outline, to show the "shape" of the ReadChip routine


bErrL:=0;//To initialize this flag
         //"0" means no error seen to this point

//===AAAAA==========================
//call TMExtendedStartSession
//if (problem) then begin bErrL:=10;//Be sure to keep the
                        //different values bErrL can be set to
                        //un-duplicated
                        //     end;//flag problem

if bErrL=0 then begin// Yes... you can be more "clever"... why risk it?


//===AAAAA==========================
//call TMValidSession// (instance 13c21a)
//... not really needed here, "should" still be
//    valid so soon after the call of TMExtendedStartSession. Here mainly to
//    illustrate how it works.
//Similar blocks can be "sprinkled" in what follows as you see fit

//if (problem) then begin bErrL:=20;
                        //     end;//flag problem
   end;//call TMValidSession (instance 13c21a)


//===BBBBB==========================
//We're now "connected" to the adapter, the TMEX API... so
//   now we start sending commands to the chips on the
//   MicroLan
if bErrL=0 then begin
//Issue a "reset" to all of the chips on the MicroLan
//This is a bit like doing a power cycle to any bit
//    of mis-behaving electronics. Note: We are NOT
//    re-setting our "connection" to the TMEX API an
//    the adapter between the PC and the MicroLan...
//    We are just resetting all of the chips ON the
//    MicroLan.

//(Issue the Reset command)
//if (problem) then begin bErrL:=40; //(bErrL:=30-39 reserved for other purposes, to be
explained later)

                        //     end;//flag problem

   end;//Issue "reset" to chips on MicroLan


//===BBBBB==========================
if bErrL=0 then begin
//Tell all but one of them to go to sleep
//if (problem) then begin bErrL:=50;
                        //     end;//flag problem

   end;////Tell all but one of them to go to sleep


//===CCCCC==========================
if bErrL=0 then begin
//Do things with the chip which is not asleep...
//   This "Do things" block may be large, may
//   have multiple steps. Will be chip specific
//   (with some common themes.)
//If, say, reading from a sensor, you should postpone,
//   separate out into separate code,
//   USING the results from the sensor
//   until you are OUT of the "use MicroLan" stuff
//if (problem) then begin bErrL:=... 70-249 reserved for any
                        //bErrL:=s which may be needed in this block
                        //     end;//flag problem

   end;//Do things with the chip which is not asleep...


//===AAAAA==========================
//Done with MicroLan, so now release resources, release lock on it.
if (session is open) then begin
//call TMEndSession
//if (problem) then begin bErrL:=250;
                        //     end;//flag problem

   end;//call TMEndSession

//Done using the MicroLan, but don't fail, just after using it to report how things went...
if bErrL<>0 then DoWhatReportingOfErrorYouWantTo;


//NOW use things you may have collected while using the MicroLan,
//   e.g. sensor readings.... if bErrL is still zero at this point.
//   (If it isn't, you can't be sure that you did collect what you
//   went to the MicroLan for.
if bErrL=0 DoThingsIfNeeded;

end;//ReadChip;

==== END PHASE ONE VERSION ======================

The "code" above won't run. It is just a sketch of the heart of a (slightly) bigger program (DS048)

======================================

======================================

This was "phase 2" of the program's development.

It is pretty well along at this stage, believe it or not!

"All" that is left is "the heart" of the program... the parts in sections "B" and "C", and the interpretation of whatever is returned from "the chip"...

We will also need to arrange for all of it to happen twice, with slightly different "stuff" in the "section C, talk to chip" part. (In the demo program, we're just using two buttons clicked by the user to trigger the two parts.

That may seem like an awful lot "left to do", and it is, in some ways....

But by having all of this, "the skeleton" up and running, before trying to install "the heart", we have set the stage for easy completion of what is, it must be said, "the hard part".

Those who are new to working with 1-Wire chips would do well to REALLY STUDY the following. It is the skeleton which is always present, even if in varied forms. Without these "boring bits", the "clever bits" of isolating the chip you want to speak to, and the actual "speaking to it" can't be done.

By the way... before we enter the code you see, suitable values have been put into wPortNum wAdapterType.

The following variables were available. They were declared as global variables in a bit of sloppy programming... but there WAS (and is) a reason for "breaking the rule" here.

wPortNum,wAdapterType:word;
    liSessionHandle:longint;//TMEX API notes called for 32-bit
       //UNsigned... but then gave example where "if (it)<0 then..."
       //appeared. So I am using Delphi longint, which is 32 bit SIGNED
    siResult:smallint;////TMEX API notes called for 16-bit
       //UNsigned... but then (in TMSessionEnd.. etc?) gave example
       //where "if (it)<0 then..." appeared. So I am using
       // Delphi smallint, which is 16 bit SIGNED



//"

====

Phase Two...

procedure DoWhatReportingOfErrorYouWantTo;//SR of ReadChip
begin
showmessage('Write code for DoWhatReportingOfErrorYouWantTo'+chr(13)+
  'bErrL='+inttostr(bErrL)+chr(13)+
  'bErrL1='+inttostr(bErrL1));
laRes0.caption:='Read chip AS FAR AS IT SO FAR GOES was **NOT** successful.';
laRes1.caption:='';
end;//DoWhatReportingOfErrorYouWantTo... SR of ReadChip

procedure DoThingsIfNeeded;//SR of ReadChip
begin
laRes0.caption:='ReadChip still needs more work';
laRes1.caption:='Read chip AS FAR AS IT SO FAR GOES was successful.';
end;//DoThingsIfNeeded... SR of ReadChip


begin
//This is a rough outline, to show the "shape" of the ReadChip routine


bErrL:=0; //To initialize these flag variables
bErrL1:=0;//"0" in bErrL means no error seen to this point
          //If bErrL<>0, then value in bErrL1 may give further information,
          //   see sourcecode... what you are reading now!

//===AAAAA==========================
//Call TMExtendedStartSession

//showmessage(inttostr(wPortNum)+'  '+inttostr(wAdapterType));<<for prgm testing

liSessionHandle:=TMExtendedStartSession(wPortNum,wAdapterType,nil);
//Note the "nil" as the third parameter. Right for Pascal (Delphi/ Lazarus)
//  in place of "null" in other languages

//In tests, at least with a LinkUSB adapter from iButtonLink,
//  TMExtendedStartSession seemed remarkably forgiving! Many times it
//  "should" not have worked due to bad values in wPortNum or wAdapterType
//  it DID work. Hmmm.

if liSessionHandle=0 then bErrL:=10;//Port not available.
if liSessionHandle<0 then begin
       bErrL:=12;//Other error, see TMEX Session Error Return Codes
          bErrL1:=240;
          if liSessionHandle=-200 then bErrL1:=200;// INVALID_SESSION -  session not valid
          if liSessionHandle=-201 then bErrL1:=201;// HS_NOT_FOUND -  Hardware_Specific
driver not found and is required
          if bErrL1=240 then bErrL1:=1;//Other error encountered (Not in Dallas docs
              //for TMEX API ver 3.10)
        end;//liSessionHandle<0
          //end of flag problems code for call of TMExtendedStartSession

//N.B. If (bErrL=0) or (bErrL>19) later (at TMEndSession) we will call TMEndSession to
//  close the session, even if we didn't manage to do with it all that we
//  wanted to. Only for bErrL:=1 to 19 (inclusive) will we NOT call TMEndSession,
//  because those error codes are reserved to say "we didn't succeed in
//  opening a session.

//TO BE DECIDED... does it matter if we do EXTRA TMEndSessions? As in the case
//  where a session ceased to be valid. I would be inclined to think it does
//  NOT matter to do EXTRAS, but probably WOULD matter to fail to do one when
//  it should be done. (TMValidSession calls should assign a bErrL of 20 or higher
//     if they fail.)

//===AAAAA==========================
//Consider calling TMValidSession
if bErrL=0 then begin// Yes... you can be more "clever"... why risk it?
siResult:=TMValidSession(liSessionHandle);// (instance 13c21a)
//... not really needed here, "should" still be
//    valid so soon after the call of TMStartSession. Here mainly to
//    illustrate how it works.

//Similar blocks can be "sprinkled" in what follows as you see fit

//TMEX API notes said TMValidSession returned 16-bit
     //UNsigned... but then gave example where "if (it is less than 0) then..."
     //appeared. So I am using Delphi smallint, which is 16 bit SIGNED

if siResult<0 then begin
        bErrL:=20;//Other error, see TMEX Session Error Return Codes
        //N.B.: For additional instances of this "call TMValidSession"
        //  code, different bErrL codes should be assigned.
          bErrL1:=240;
          if siResult=-200 then bErrL1:=200;// INVALID_SESSION -  session not valid
          if siResult=-201 then bErrL1:=201;// HS_NOT_FOUND -  Hardware_Specific driver not
found and is required
          if bErrL1=240 then bErrL1:=1;//Other error encountered (Not in Dallas docs
              //for TMEX API ver 3.10)
        end;//siResult<0
        //end of flag problems code for call of TMValidSession
   end;//call TMValidSession (instance 13c21a)

//===BBBBB==========================
//We are now "connected" to the adapter, the TMEX API... so
//   now we start sending commands to the chips on the
//   MicroLan...
//Consider resetting all 1-wire chips on the MicroLan
if bErrL=0 then begin
//Issue a "reset" to all of the chips on the MicroLan
//This is a bit like doing a power cycle to any bit
//    of mis-behaving electronics. Note: We are NOT
//    re-setting our "connection" to the TMEX API an
//    the adapter between the PC and the MicroLan...
//    We are just resetting all of the chips ON the
//    MicroLan.

//(Issue the Reset command)
//if (problem) then begin bErrL:=40; //(bErrL:=30-39 reserved for other purposes, to be
explained later)
                        //     end;//flag problem

   end;//Issue "reset" to chips on MicroLan


//===BBBBB==========================
//Consider putting to sleep all of the chips APART FROM
//the one you want to. (This is how you can send commands
//down the wire they are all connected to without them all
//reacting.)
if bErrL=0 then begin
//Tell all but one of them to go to sleep
//if (problem) then begin bErrL:=50;
                        //     end;//flag problem

   end;////Tell all but one of them to go to sleep


//===CCCCC================================================
==
//Consider doing things with the one chip that is awake
if bErrL=0 then begin
//Do things with the chip which is not asleep...
//   This "Do things" block may be large, may
//   have multiple steps. Will be chip specific
//   (with some common themes.)
//If, say, reading from a sensor, postpone,
//   separate out into separate code,
//   USING the results from the sensor
//   until you are OUT of the "use MicroLan" stuff
//if (problem) then begin bErrL:=... 70-249 reserved for any
                        //bErrL:=s which may be needed in this block
                        //     end;//flag problem

   end;//Do things with the chip which is not asleep...

//===AAAAA==========================
//Consider calling TMEndSession, as we are done with MicroLan,
//so now release resources, release lock on it.

//NOTE THAT THIS ONE IS SPECIAL... sometimes we do it, even if
//  errors arose along the way. We only don't do it when we
//  didn't succeed in opening the session, which will be indicated
//  by a value in bErrL of between 1 and 19, inclusive.

if (bErrL=0) or (bErrL>19) then begin
siResult:=TMEndSession(liSessionHandle);
//TMEX API notes said TMEndSession returns 16-bit
       //UNsigned... but then gave example where "if (it is less than 0) then..."
       //appeared. So I am using Delphi smallint, which is 16 bit SIGNED
if siResult<0 then begin
      bErrL:=250;//For details of error see TMEX Session Error Return Codes
          bErrL1:=240;
          if siResult=-200 then bErrL1:=200;// INVALID_SESSION -  session not valid
          if siResult=-201 then bErrL1:=201;// HS_NOT_FOUND -  Hardware_Specific driver not
found and is required
          if bErrL1=240 then bErrL1:=1;//Other error encountered (Not in Dallas docs
              //for TMEX API ver 3.10)
       end;//siResult<0
          //end of flag problems code for call of TMEndSession
   end;//call TMEndSession

//Done using the MicroLan, so now we can...
if bErrL<>0 then DoWhatReportingOfErrorYouWantTo;

/// ... and....
//NOW use things you may have collected while using the MicroLan,
//   e.g. sensor readings.... if bErrL is still zero at this point.
//   (If it isn't, you can't be sure that you did collect what you
//   went to the MicroLan for.
if bErrL=0 then DoThingsIfNeeded;

end;//ReadChip;



=====
iDMLAdapterType:=5;(*Adapter types..
   1:DS9097 with no suffix, 9097E
   5:DS9097U, 9097U-9*)
   6:USB (?)
========
"

===========================================

===============================================

Phase Three...

A lot of stuff has been done to the code. But the new stuff is mostly in the "B" and "C" blocks.

A "switch" has been introduced, and it is passed to the code as a new parameter of the SR call. I've called the parameter wWhatAction. wWhatAction is referenced just once, deep within the code, and selects the "script" to follow inside the "talk to the chip" part of "the framework". The values in wWhatAction are arbitrary, but I will usually use the number of the command I intend to issue as the "code" for the wWhatAction "switch" value.

At the same time, I've changed what was (foolishly, as it turns out.. but I'm not going to take the time to go back and change everything from the start of this!)... was foolishly called "ReadTtureFromChip" to TalkTo1Wire.

Several new variables have been brought into use, and something else had to have a "suitable value" in it before the code below began to run.

Note that I've added a sErrMsgL, too. If bErrL is 0, the contents of sErrMsgL are meaningless. Otherwise, they tell you a bit about the error which was encountered. (I've re-worked some of the earlier code to use sErrMsgL, too.)

The first major work in going from Phase Two to Phase Three was the coding of the innocent little line in Phase Two saying "Issue the Reset Command".

I am using the TMSetup command to reset all of the chips on the MicroLan. It looks like maybe the 1-Wire designers intended that we should do a TMSetup once, at the start of a program's run, and use TMTouchReset after that... but I wanted the more thorough checks which are part of TMSetup, and so am calling it again and again while my program runs. Only once per "TMExtendedStartSession"... but more than once per program's execution. (I will use TMTouchReset if I need to reset the chips a second time, after a TMExtendedStartSession, but before a TMEndSession. (bErrL code 30-39 have been set aside for TMTouchReset's use.)

Then the development process moved on to the "put all the chips, except one, to sleep. More "excitement"!

This trick of putting all but one of the chips to sleep is how you can send commands down the wire they're all connected to without them all reacting. There is one command that even a "sleeping" chip responds to... the "reset" command.

Here's a little "wrinkle"... The TMEX command I am going to use, TMAccess, does a TMTouchReset as part of itself (i.e. part of TMAccess)

However, the (documented) return values which can arise from a call of TMAccess do not include all of the values which can be returned by a TMTouchReset.

Remember also that you can't do a TMTouchReset until you have done a TMSetup... which ALSO resets all the chips on the MicroLan

For now, I'm "going with" doing a TMSetup, as above, AND a TMAccess, even though that means that the MicroLan gets an "extra" reset. This will entail a time cost. If you need hyper-fast reading of multiple sensors, you may want to look into a different "skeleton" for your program... but I'd work through the rest of THIS approach first, if I were you! If a TMSetup must happen after each TMExtendedStartSession, you may find the headaches of doing one just once significant.

(As before, the TMEX documentation is internally inconsistent. It says that TMAccess returns a "short"-type value, in TMEX terms an UNsigned 16-bit number, but then goes on to say that it can return negative numbers... so I used a Delphi smallint-type variable, capable of handling SINGED 16-bit numbers.

For the first time, one "step" of our plan is going to require TWO TMEX calls. We will do a TMRom first, to put the unique ID of the chip we want to stay awake where it is needed for the call of TMAccess which comes after the call of TMRom. But I'm going to talk about the call of TMAccess first.

(The "unique ID" of the chip is the 16 hex character ID string which we can use OneWireViewer to read from the chips we happen to have.)

The chip id always ends with a two hex character "family ID" for the sort of chip that it is, e.g. $10 for DS1920s, $28 for DS18B20s. The family code for a given type of chip is given in the chip's datasheet.

When we got to writing the code to put all the chips, bar one, to sleep (using TMAccess) two new data structures were needed... and I created one more, not for the needs of TMEX, but to make life easier for me in the "outer" parts of this program.

I'm going to work through these new data structures in the next few paragraphs.

This program is only a minor "demonstrator". I am going to give it one frill, though, as a hint of the sort of things that arise in "real" programs for working with MicroLans and 1-Wire chips.

I haven't said much, to date, about the general user interface.

In most respects, it is unremarkable. You put the port the adapter is on into an edit box. You put the adapter type into an edit box. There are various mechanisms at play to disable the "Do Tture Pt1" and "Do Tture Pt1" buttons until sensible values are in the edit box.

There are also TWO edit boxes for "chip ID". The great beauty of the 1-Wire design is that multiple chips can share one bus. So even our little demonstrator should access more than one chip.

There are also radio buttons to allow the user to say which chip should be read.

Here are the chip IDs of the two chips I was working with...

Remember: Each Dallas chip has a unique ID, so you will need to use different numbers if you run the program...the ID numbers of YOUR chips.

(A word of warning, by the way, for some reason, in some parts of the Dallas documentation, chip IDs are written in the other direction, but a byte at a time, so...

B000080005472610 becomes...
10264705008000B0

Don't ask me why. Just be on guard. I will always present chip IDs with the family code at the right hand end. Thus, with the right data sheets, you can see that I had a DS1920 (family code $10) and a DS18B20 (family code $28)

Now... I'm a mere human. I am quite happy to put the chip ID codes into elements of an array, which is what I've done, calling the array sChipID. The first element is sChipID[0]. That array is the new data structure to make life easier for me in the "outer" parts of this program.

AND... A minor point: From the user's perspective, the two chips are "Chip A" and "Chip B". Internally, in my program, they are called Chip0 and Chip1.

The TMEX API doesn't want the chip ID in a string, as ASCII characters. It wants the chip ID in an array of, it says, elements of data type "short"... by which, the documentation says, they mean 16-bit unsigned integers. But... as we have seen elsewhere, sometimes even when they say something's data type should be 16-bit UNsigned, they want to put negative numbers in it. I am again going to guess that what they "really" wanted was an array of 16-bit signed values, and use the Delphi data type "smallint". (Don't slip and type "shortint"... Delphi has one of those, too... and it is different!)(Don't be tempted, either, to use an array of Delphi type byte. That won't work, as the TMEX API is assuming that the bytes it wants are stored with "waste" bytes between them. (It accesses the part of the computer's memory where the bytes are quite directly, using a pointer to where the array starts.)

And we're not done with this yet. In the Dallas documentation, the array is called "ROM". Both in this instance, and in other places, Dallas uses the word ROM in a way that isn't consistent with my idea of what "ROM" is about. I'm going to call the array we need "siNumbersForTMRom", because this little array is used by the TMRom routine. Just remember, when reading the Dallas TMEX API help file that they call this array "ROM".

And now we go on to the NEXT problem. In the documentation, the array is referenced as ROM[8]. To me, that implies an array of NINE elements. And that may be exactly what Dallas wants. To be on the safe side, I will declare the array as [0..8]. From what I've done in the past, I can see that for passing chip IDs to TMRom, I use array elements 0..7. (I believe element 8 is used... in places we aren't going.)

So... that's two of the three new data structures discussed.

The third is called by Dallas "state_buffer", and is declared thus...

unsigned char state_buffer[15360];

I'm going to call it "bTMEXstatebuffer" in my sourcecode. As with the question of the "8" associated with NumbersForTMRom (aka "ROM"), I'm going to play safe, declare the array to have both an element 0 and an element 15360. Yes... 15k. There are some 1-Wire chips with significant EEPROM, and I suppose the large buffer is used when transferring data to and from storage on the 1-Wire chip.

As for the "unsigned char" type, in Dallas-speak: I've translated that to a Delphi "byte" type array element in the past without problems.

Whew! That's the "scene set". Now you'll see these new data structures in use in a moment.

First we'll do the TMRom call. It "stuffs" the characters of the chip's ID into the bTMEXstatebuffer array. You have to put them in the siNumbersForTMRom array first, sigh. And the ORDER is important.

I've provided the procedure FillsiNumbersForTMRom, to take care of filling siNumbersForTMRom.

The basic TMAccess call looks like this:

siResult:=TMRom(liSessionHandle,@bTMEXstatebuffer,@FillsiNumbersForTMRom);

Mostly what we've seen before... apart from the fact that it uses the two new data structures, and that it uses the Pascal/ Delphi/ Lazarus "@" operator.

That "@" tells Delphi not to use the values in either array. Instead the addresses of the starts of the arrays are passed to TMRom. This isn't a technique I often use, so I can't tell you a lot about it. I can tell you that this is what you need here, because of the way TMRom was written.

For some details, you will have to read the sourcecode. (Mainly the provision for various error messages which can come back from TMEX after a call to one of its routines.

Whew! That was a BUNCH of stuff to wrestle with!

Things get easy again now.

"All" that's left is...

Nearly done!... with this crude demonstrator. The phase after that: Package the elements in a more easily reused form.

Phase Four

Here you have the code, more or less complete.

What comes after this is "re-packaging" the code, so that the "boring bits" can be "hidden away" in a stand alone unit, and a higher level system of calling elements and "parts" we want can be employed.

However, I hope the following, which can be downloaded as part of the zip file DS048.zip with all the files you need to compile this project will be useful to you in seeing HOW 1-Wire work is done. Sometimes, when "stuff" is "wrapped" in units, it becomes less easy to analyze?

unit DS048u1;

(*N.B: According to the TMEX ver 3.10 API help file, the following "type"
    names in the TMEX documentation are used as indicated... I have
    prefixed each line with the equivalent Delphi (ver 4, anyway) type

    BUT! You have to take some of this with a pinch... or more... or salt,
    unless I'm missing something.

    In the TMExtendedStartSession documentation, it clearly says that
    if the function returns a negative 1, then it means (something).

    But we are told to assign what TMExtendedStartSession returns to
    a variable of type "long", in the example.

    However, elsewhere, we were told that "long", in their terms, is
    a 32-bit UNSIGNED integer...???

    Apply common sense, and some optimism, I guess.

    To be fair, I have skirted over the word "far" in one part of
    the documentation... but in the example of using
    TMExtendedStartSession, the "far" is absent.... to quote...

long session_handle;
short PortNum = 1, PortType = 1;

/* attempt to get a session on Port */
session_handle = TMExtendedStartSession(PortNum,PortType,NULL);

if (session_handle > 0)
{
    /* call TMEX API function with session_handle */
    ...
}
else if (session_handle == 0)
{
    /* port not available */
    ...
}
else if (session_handle == -1)    /* <<<<<<<<<<<<<
{
    /* failure, indicated type does not have a driver */
    ...

End quote. I rest my case. As I said... hope and pray, but,
they SAY.....

    What Delphi  TMEX      .... i.e...
    calls...     calls...

    word         short     16 bit unsigned integer
    longword     long      32 bit unsigned integer

    ===
    Delphi further says...

    Delphi type   ... is...
    Smallint      16 bit signed integer
    Longint       32 bit signed integer

    *)

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Inifiles, iBTMEXPW;
  //N.B.: This code will only compile if at least iBTMEXPW.dcu is available.
  //(I usually just put a copy in the project's sourcecode folder. The .dcu
  // comes (free) from Maxim/ Dallas as part of the SDK/ 1-Wire drivers.

const vers='1/1/14b';
      //started 30 Dec 13, along road to DS025B
      sReadyToTry='You have POSSIBLY valid data. But, while, for example, your port number
IS a number, it may not be the RIGHT number';
      sReadyToTryNOT='Enter numbers for Port and Adapter and string of 16 hex characters for
chip ID.';

type
  TDS048f1 = class(TForm)
    laPortNum: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    ePortNum: TEdit;
    eAdapterType: TEdit;
    eChipID0: TEdit;
    buDoTturePt1: TButton;
    buQuit: TButton;
    laReadChipEnableInfo: TLabel;
    laRes0: TLabel;
    laRes1: TLabel;
    laRes2: TLabel;
    laRes3: TLabel;
    eChipID1: TEdit;
    Label1: TLabel;
    GroupBox1: TGroupBox;
    rbReadChip0: TRadioButton;
    rbReadChip1: TRadioButton;
    buDoTturePt2: TButton;
    laTtureResult: TLabel;
    procedure ePortNumChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure buQuitClick(Sender: TObject);
    procedure buDoTturePt1Click(Sender: TObject);
    procedure eAdapterTypeChange(Sender: TObject);
    procedure eChipID0Change(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure eChipID1Change(Sender: TObject);
    procedure buDoTturePt2Click(Sender: TObject);
  private
    { Private declarations }
    boGoodPortNumber,boGoodAdapterType,boGoodChipID0,boGoodChipID1:boolean;
    wTtureCentiK:word;

    //Variables specifically for TMEX
    wPortNum,wAdapterType:word;
    liSessionHandle:longint;//TMEX API notes called for 32-bit
       //UNsigned... but then gave example where "if (it)<0 then..."
       //appeared. So I am using Delphi longint, which is 32 bit SIGNED
    siResult:smallint;////TMEX API notes called for 16-bit
       //UNsigned... but then (in TMSessionEnd.. etc?) gave example
       //where "if (it)<0 then..." appeared. So I am using
       // Delphi smallint, which is 16 bit SIGNED
    siNumbersForTMRom:array [0..8] of smallint;//Be careful... Delphi also has
                                     //a shortint... but it is different.
                                     //We want, here and for siResult, and
                                     //smallint gives to us, a
                                     //16-bit signed integer type.
                                     //Used by TMRom
    bTMEXstatebuffer:array[0..15360] of byte;//Used by TMRom, TMAccess

    //end TMEX variables

    sChipID: array[0..1] of string[16];
    procedure SeeIfTimeToEnableReadChip;
    procedure TalkTo1Wire(wWhatAction:word);
       //When TalkTo1Wire executed, much will be the same every time.
       //At the heart of it, there will be a "switch" controlled
       //      by wWhatAction to determine what messages go to
       //      the chip to which we have made a connection.
       //The values in wWhatAction are arbitrary, but I will usually
       //      use the number of the command I intend to issue as the
       //       "code" for the wWhatAction "switch" value.
       //See top of TalkTo1Wire for defined wWhatAction

    procedure KludgeDelay;
    function sTtureCfrmCentiK(wTture:word):string;
    function wRawTTureToCentiK(bTtureLo,bTtureHi,bChipFam:byte):word;

  public
    { Public declarations }
  end;

var
  DS048f1: TDS048f1;

implementation

{$R *.DFM}
{$R+}

procedure TDS048f1.FormCreate(Sender: TObject);
var dfIniFile:TIniFile;//"df" in name from "datafile".
begin
wPortNum:=999;//Init
wAdapterType:=999;//Init
laRes0.caption:='';
laReadChipEnableInfo.caption:=sReadyToTryNOT;
boGoodPortNumber:=false;
buDoTturePt1.enabled:=false;
buDoTturePt2.enabled:=false;

//--------------------------------------------------------------
//Read from ini file, or, ini file absent, use hard-coded defaults here.
//Note: There are OnChange handlers on many of the edit boxes

dfIniFile:=TIniFile.Create(ExtractFilePath(Application.ExeName)+'DS048ini.txt');

with dfIniFile do begin
   ePortNum.text:=ReadString('Port','Number','2');
   eAdapterType.text:=ReadString('Port','AdapterType','2');
   eChipID0.text:=ReadString('Chip','ID-Chip A','1111222233334444');
   eChipID1.text:=ReadString('Chip','ID-Chip B','1111222233334444');
   end;//with...

dfIniFile.Free;
//End of "Read from ini..."

end;

procedure TDS048f1.SeeIfTimeToEnableReadChip;
begin
if boGoodPortNumber and
   boGoodAdapterType and
   boGoodChipID0 and
   boGoodChipID1 then begin
     laReadChipEnableInfo.caption:=sReadyToTry;
     buDoTturePt1.enabled:=true;
     buDoTturePt2.enabled:=true;
     end//no ; here
   else begin
     laReadChipEnableInfo.caption:=sReadyToTryNOT;
     buDoTturePt1.enabled:=false;
     buDoTturePt2.enabled:=false;
     end;
end;//SeeIfTimeToEnableReadChip

procedure TDS048f1.buQuitClick(Sender: TObject);
begin
close;
end;

procedure TDS048f1.ePortNumChange(Sender: TObject);
begin
boGoodPortNumber:=true;
try
  wPortNum:=StrToInt(ePortNum.text);
  except
  boGoodPortNumber:=false;
  end;//try.. except
SeeIfTimeToEnableReadChip;
laRes2.caption:=inttostr(wPortNum);
end;//ePortNumChange

procedure TDS048f1.eAdapterTypeChange(Sender: TObject);
begin
boGoodAdapterType:=true;
try
  wAdapterType:=StrToInt(eAdapterType.text);
  except
  boGoodAdapterType:=false;
  end;//try.. except
SeeIfTimeToEnableReadChip;
end;//eAdapterTypeChange


procedure TDS048f1.FormClose(Sender: TObject; var Action: TCloseAction);
var dfIniFile:TInifile;
begin
 dfIniFile:=TIniFile.Create(ExtractFilePath(Application.ExeName)+'DS048ini.txt');
 with dfIniFile do begin
   WriteString('Port','Number',ePortNum.text);
   WriteString('Port','AdapterType',eAdapterType.text);
   WriteString('Chip','ID-Chip A',eChipID0.text);
   WriteString('Chip','ID-Chip B',eChipID1.text);
   end;//with...
 dfIniFile.Free;

end;//FormClose

procedure TDS048f1.buDoTturePt1Click(Sender: TObject);
begin
TalkTo1Wire($44);//Do a "Convert Tture". Should include "and wait 500ms", in
//case on parasitic. Can come out, if speed needed, but will
//require some special stuff.
end;// buDoTturePt1Click

procedure TDS048f1.buDoTturePt2Click(Sender: TObject);
begin
TalkTo1Wire($BE);//Do a "ReadScratchpad".
//For now, puts two of the read bytes into special global variables...
//   the bytes returned should go someplace more general.
//Presumes a prior "Convert Tture"
end;//DoTturePt2Click

procedure TDS048f1.TalkTo1Wire(wWhatAction:word);
//This is a rough outline, to show the "shape" of the TalkTo1Wire routine

//When TalkTo1Wire executed, much will be the same every time.
//At the heart of it, there will be a "switch" controlled
//      by wWhatAction to determine what messages go to
//      the chip to which we have made a connection.
//The values in wWhatAction are arbitrary, but I will usually
//      use the number of the command I intend to issue as the
//       "code" for the wWhatAction "switch" value.
//wWhatAction set to 0 inside each handler, as part of "was undefined
//      wWhatAction requested" handling.
//Defined wWhatActions...
//  $44: Convert Tture. Valid for DS1820 (family $10)
//                                DS18B20 (family $28)
//       Issues a "Convert Tture" command... and(?) does a delay?
//                                       ... and(?) strong pullup?
//  $5E: Read Scratchpad. Valid for, at least, DS1820, DS18B20
//      At 1/1/14, it was putting results in too-specific global vars
//      Needs a "check checksum" part.

var bTmpL,bErrL,bErrl1:byte;
    boWhatActionHandlerFound:boolean;
    sErrMsgL:string;
    bTtureLo,bTtureHi:byte;//KLUDGE-rework in more general state
procedure DoWhatReportingOfErrorYouWantTo;//SR of ReadChip
begin
showmessage('Write code for DoWhatReportingOfErrorYouWantTo'+chr(13)+
  'bErrL='+inttostr(bErrL)+chr(13)+
  'bErrL1='+inttostr(bErrL1)+chr(13)+
  'sErrMsgL='+sErrMsgL);
laRes0.caption:='Read chip AS FAR AS IT SO FAR GOES was **NOT** successful.';
laRes1.caption:='';
end;//DoWhatReportingOfErrorYouWantTo... SR of ReadChip

procedure DoThingsIfNeeded;//SR of ReadChip
begin
laRes0.caption:='ReadChip still needs more work';
laRes1.caption:='Read chip AS FAR AS IT SO FAR GOES was successful.';
end;//DoThingsIfNeeded... SR of ReadChip

procedure FillsiNumbersForTMRom(bWhichChip:byte);//SR of ReadChip
var bCount:byte;
//NB: "Family code" goes in siNumbersForTMRom[0], and rest fill with
//  the parts of the ID code from family code end to other end.
//I.e. if the family code were 28, and the chip ID were...
//  1122334455667728, then  siNumbersForTMRom[0],[1],[2], etc would be..
//  28, 77, 66, 55, 44, 33... etc, with 11 going in siNumbersForTMRom[7]
begin
for bCount:=0 to 7 do begin
   siNumbersForTMRom[7-bCount]:=strtoint('$'+copy(sChipID[bWhichChip],(bCount*2)+1,2));
// showmessage(inttostr(strtoint('$'+copy(sChipID[bWhichChip],(bCount*2)+1,2)))); // prgm <<for
testing
   end;//for
end;//FillsiNumbersForTMRom... //SR of ReadChip

begin //ReadChip
//This is a rough outline, to show the "shape" of the ReadChip routine

bErrL:=0; //To initialize these flag variables
bErrL1:=0;//"0" in bErrL means no error seen to this point
          //If bErrL<>0, then value in bErrL1 may give further information,
          //   see sourcecode... what you are reading now!
sErrMsgL:='No Error Seen';

//===AAAAA==========================
//Call TMExtendedStartSession

//showmessage(inttostr(wPortNum)+'  '+inttostr(wAdapterType));<<for prgm testing

liSessionHandle:=TMExtendedStartSession(wPortNum,wAdapterType,nil);
//Note the "nil" as the third parameter. Right for Pascal (Delphi/ Lazarus)
//  in place of "null" in other languages

//In tests, at least with a LinkUSB adapter from iButtonLink,
//  TMExtendedStartSession seemed remarkably forgiving! Many times it
//  "should" not have worked due to bad values in wPortNum or wAdapterType
//  it DID work. Hmmm.

if liSessionHandle=0 then bErrL:=10;//Port not available.
if liSessionHandle<0 then begin
       bErrL:=12;//Other error, see TMEX Session Error Return Codes
          bErrL1:=240;
          if liSessionHandle=-200 then begin
             bErrL1:=200;// INVALID_SESSION -  session not valid
             sErrMsgL:='INVALID_SESSION -  session not valid';
             end;
          if liSessionHandle=-201 then begin
             bErrL1:=201;// HS_NOT_FOUND -  Hardware_Specific driver not found and is required
             sErrMsgL:='HS_NOT_FOUND -  Required Hardware_Specific driver not found';
             end;
          if bErrL1=240 then begin
             bErrL1:=1;//Other error encountered (Not in Dallas docs
              //for TMEX API ver 3.10)
             sErrMsgL:='Other error, not in Dallas docs, TMEX API ver 3.10';
             end;
        end;//liSessionHandle<0
          //end of flag problems code for call of TMExtendedStartSession

//N.B. If (bErrL=0) or (bErrL>19) later (at TMEndSession) we will call
//  TMEndSession to close the session, even if we didn't manage to
//  do with it all that we wanted to.
//  Only for bErrL:=1 to 19 (inclusive) will we NOT call TMEndSession,
//  because those error codes are reserved to say "we didn't succeed in
//  opening a session.

//TO BE DECIDED... does it matter if we do EXTRA TMEndSessions? As in the case
//  where a session ceased to be valid. I would be inclined to think it does
//  NOT matter to do EXTRAS, but probably WOULD matter to fail to do one when
//  it should be done. (TMValidSession calls should assign a bErrL of 20 or higher
//     if they fail.)

//===AAAAA==========================
//Consider calling TMValidSession... i.e. do it, unless bErrL shows we're
//   already past a place where an error makes doing more futile.
if bErrL=0 then begin// Yes... you can be more "clever"... why risk it?
siResult:=TMValidSession(liSessionHandle);// (instance 13c21a)
//... not really needed here, "should" still be
//    valid so soon after the call of TMExtendedStartSession. Here mainly to
//    illustrate how to use a TMValidSession should you want to insert one.

//Similar blocks can be "sprinkled" in what follows as you see fit,
//    but be careful with the bErrL and bErrL1 codes to distinguish
//    any failure from all others.

//TMEX API notes said TMValidSession returned 16-bit
     //UNsigned... but then gave example where "if (it)<0 then..."
     //appeared. So I am using Delphi smallint, which is 16 bit SIGNED

if siResult<0 then begin
        bErrL:=20;//Other error, see TMEX Session Error Return Codes
        //N.B.: For additional instances of this "call TMValidSession"
        //  code, different bErrL codes should be assigned.
          bErrL1:=240;
          if siResult=-200 then begin
             bErrL1:=200;
             sErrMsgL:='INVALID_SESSION -  session not valid';
             end;
          if siResult=-201 then begin
             bErrL1:=201;
             sErrMsgL:='HS_NOT_FOUND -  Required Hardware_Specific driver not found';
             end;
          if bErrL1=240 then begin
             bErrL1:=1;
             sErrMsgL:='Other error, not in Dallas docs, TMEX API ver 3.10';
             end;
        end;//siResult<0
        //end of flag problems code for call of TMValidSession
   end;//call TMValidSession (instance 13c21a)

//============= vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// HERE BEGINS A BLOCK OF "maybe later" CODE. IF BROUGHT INTO USE, IT
// WILL NEED A LOT OF TESTING............
(*
//(Issue the Reset command)... an alternative way to reset the chips on the
//  MicroLan... but for SUBSEQUENT resets, after a TMSetup has been done
//  since the previous TMExtendedStartSession (without TMEndSession in between)

//Note that TMTouchReset must not be called before a TMSetup has been called...
//  but TMTouchReset can detect presence pulses, and distinguish between the
//  "alarming" and "not alarming" variations of them.

//This TMTouchReset code not thoroughly tested.

siResult:=TMTouchReset(liSessionHandle);
//TMEX API notes said TMTouchReset returned 16-bit
     //UNsigned... but then gave example where "if (it)<0 then..."
     //appeared. So I am using Delphi smallint, which is 16 bit SIGNED

//After TMTouchReset, a slew of messages (via siResult) are possible.
if siResult=0 then begin
     //We are happy... the reset seems to have gone okay.
     //No presence pulse was detected... which doesn't concern us
     //     but I've put this bit of code in for future expansion
     end;
if siResult=1 then begin
     //We are happy... the reset seems to have gone okay.
     //A "non-alarming presence pulse" was detected... which doesn't concern us
     //     but I've put this bit of code in for future expansion.
     //     "Non-alarming presence pulse": Presence pulses come in two
     //         "flavors". There at least one chip to send a presence pulse,
     //         but no chip was sending an alarm as well.
     end;
if siResult=2 then begin
     //We are happy... the reset seems to have gone okay.
     //An "alarming presence pulse" was detected... which doesn't concern us
     //     but I've put this bit of code in for future expansion.
     //     "Alarming presence pulse": Presence pulses come in two
     //         "flavors". There was a chip which was sending a presence pulse,
     //         AND the chip was "alarming". (Generating the alarm message)
     end;

//Now we'll handle the various messages which can come back in siResult
//which will bother us... This is still following the call of TMTouchReset

if (bErrL=0)and (siResult=3) then begin
   bErrL:=40;

   end;//Deal with (bErrL=0)and (siResult=3)

if (bErrL=0)and (siResult=5) then begin
   bErrL:=41;

   end;//Deal with (bErrL=0)and (siResult=5)

if (bErrL=0)and (siResult<1) then begin
   bErrL:=240;
   if siResult=-1 then begin //-1
        bErrL:=44;
        bErrL1:=1;
        sErrMsgL:='Specified MicroLan has not been '+
           'initialized with a call to the TMSetup function';
        end;//-1

   if siResult=-2 then begin //-2
        bErrL:=44;
        bErrL1:=2;
        sErrMsgL:='Specified MicroLan nonexistent.';
        end;//-2

   if siResult=-3 then begin //-3
        bErrL:=44;
        bErrL1:=3;
        sErrMsgL:='Function not supported';
        end;//-3

   if siResult=-12 then begin //-12
        bErrL:=44;
        bErrL1:=12;
        sErrMsgL:='Failure to communicate with hardware adapter';
        end;//-12

   if siResult=-13 then begin //-13
        bErrL:=44;
        bErrL1:=13;
        sErrMsgL:='An unsolicited event occurred on the 1-Wire';
        end;//-13

   if siResult=-200 then begin //-200
        bErrL:=44;
        bErrL1:=200;
        sErrMsgL:='session not valid (not applicable in DOS TMEX)';
        end;//-200

   if siResult=-201 then begin //-201
        bErrL:=44;
        bErrL1:=201;
        sErrMsgL:='Hardware_Specific driver not found and is required';
        end;//-201

   if bErrL=240 then begin //(unrec -ve code)
        bErrL:=45;
        bErrL1:=99;
        sErrMsgL:='siResult was unrecognised (TMEX 3.10) error code '+
           inttostr(siResult);
        end;//(unrec -ve code)

      end;//Deal with (bErrL=0)and (siResult<1)
      //end of flag problems code for call of TMTouchReset

   end;//Issue "reset" to chips on MicroLan by TMTouchReset (Which can
       //  only be called after a TMSetup has been executed.

END OF UNTESTED "Issue TMTouchReset", the "maybe later" CODE.*)
//
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^
//--------------------------------------------------------------------



//===BBBBB==========================
//We're now "connected" to the adapter, the TMEX API... so
//   now we start sending commands to the chips on the
//   MicroLan...
//Consider resetting all 1-wire chips on the MicroLan
if bErrL=0 then begin
//Issue a "reset" to all of the chips on the MicroLan
//This is a bit like doing a power cycle to any bit
//    of mis-behaving electronics. Note: We are NOT
//    re-setting our "connection" to the TMEX API an
//    the adapter between the PC and the MicroLan...
//    We are just resetting all of the chips ON the
//    MicroLan.
//TMSetup also performs certain checks on the MicroLan,
//    such as "is it shorted"?

siResult:=TMSetup(liSessionHandle);
//TMEX API notes said TMTouchSetup returned 16-bit
     //UNsigned... but then gave example where "if (it)<0 then..."
     //appeared. So I am using Delphi smallint, which is 16 bit SIGNED

//After TMSetup, a slew of messages (via siResult) are possible.
if siResult=0 then begin
        bErrL:=40;
        bErrL1:=0;
        sErrMsgL:='TMSetup failed. That''s all that the '+
           'documentation says about the meaning of a returned zero. '+
           'Other return values are possible... with more information! '+
           'Zero seems to be a general "fail" when reason can''t be given.';
        end;
if siResult=1 then begin
     //We are happy... TMSetup went well.
     end;
if siResult=2 then begin
        bErrL:=41;
        bErrL1:=2;
        sErrMsgL:='TMSetup went ok. but MicroLan is shorted.';
     end;
if siResult=3 then begin
        bErrL:=44;
        bErrL1:=3;
        sErrMsgL:='TMSetup says MicroLan does not exist.';
        //This error message did NOT arise in some brief tests
        //  on a system WITH an iButtonLink LinkUSB plugged in...
        //  but with no MicroLan plugged into the LinkUSB
        //It DID occur if the LinkUSB was unplugged, and it was
        //  only necessary to re-connect the LinkUSB to the PC
        //  to have the program run without complaint again. (The
        //  program did not need to be re-started.)
     end;
if siResult=4 then begin
        bErrL:=45;
        bErrL1:=4;
        sErrMsgL:='TMSetup says TMSetup not supported by your hardware/OS.';
     end;

if (siResult<1) then begin
   bErrL:=240;
   if siResult=-1 then begin //-1
        bErrL:=46;
        bErrL1:=1;
        sErrMsgL:='Specified MicroLan has not been '+
           'initialized with a call to the TMSetup function';
        //It would be odd if this error arose during a call of TMSetup!
        //But it is a TMSetup/ TMTouchReset error message, and I am
        //  including a handler for it here, just in case.
        end;//-1

   if siResult=-2 then begin //-2
        bErrL:=46;
        bErrL1:=2;
        sErrMsgL:='Specified MicroLan nonexistent.';
        end;//-2

   if siResult=-3 then begin //-3
        bErrL:=46;
        bErrL1:=3;
        sErrMsgL:='Function not supported';
        end;//-3

   if siResult=-12 then begin //-12
        bErrL:=46;
        bErrL1:=12;
        sErrMsgL:='Failure to communicate with hardware adapter';
        end;//-12

   if siResult=-13 then begin //-13
        bErrL:=46;
        bErrL1:=13;
        sErrMsgL:='An unsolicited event occurred on the 1-Wire';
        end;//-13

   if siResult=-200 then begin //-200
        bErrL:=46;
        bErrL1:=200;
        sErrMsgL:='session not valid (not applicable in DOS TMEX)';
        end;//-200

   if siResult=-201 then begin //-201
        bErrL:=46;
        bErrL1:=201;
        sErrMsgL:='Hardware_Specific driver not found and is required';
        end;//-201

   if bErrL=240 then begin //(unrec -ve code)
        bErrL:=46;
        bErrL1:=99;
        sErrMsgL:='siResult was unrecognized (TMEX 3.10) error code '+
           inttostr(siResult);
        end;//(unrec -ve code)

      end;//Deal with (bErrL=0)and (siResult<1)
      //end of flag problems code for call of TMTouchReset

   end;//Issue "reset" to chips on MicroLan by TMSetup


//===BBBBB==========================
//Consider putting to sleep all of the chips APART FROM
//the one you want to. (This is how you can send commands
//down the wire they're all connected to without them all
//reacting.)

//Here's a little "wrinkle"...
//The TMEX command I am going to use, TMAccess, does a TMTouchReset
//  as part of itself (i.e. part of TMAccess)
//However, the (documented) return values which can arise from a
//  call of TMAccess do not include all of the values which can be
//  returned by a TMTouchReset.
//Remember also that you can't do a TMTouchReset until you have
//  done a TMSetup... which ALSO resets all the chips on the MicroLan
//
//For now, I'm "going with" doing a TMSetup, as above, AND a TMAccess,
//  even though that means that the MicroLan gets an "extra" reset.
//This will entail a time cost. If you need hyper-fast reading of multiple
//  sensors, you may want to look into a different "skeleton" for your
//  program. If a TMSetup must happen after each TMExtendedStartSession,
//  you may find the headaches of doing one just once significant.

//(As before, the TMEX documentation is internally inconsistent. It says
//  that TMAccess returns a "short"-type value, in TMEX terms an UNsigned
//  16-bit number, but then goes on to say that it can return negative
//  numbers... so I used a Delphi smallint-type variable, capable of
//  handling SINGED 16-bit numbers.

//For the first time, one "step" of our plan is going to require TWO
//  TMEX calls. We will do a TMRom first, to put the unique ID of the chip
//  we want to stay awake where it is needed for the call of TMAccess which
//  comes after the call of TMRom.
//(The "unique ID" of the chip is the 16 hex character ID string which
//  we can use OneWireViewer to read from the chips we happen to have.)
//The chip id always ends with a two hex character "family ID" for the
//  sort of chip that it is, e.g. $10 for DS1920s, $28 for DS18B20s.
//  The family code for a given type of chip is given in the chip's datasheet.

//First, prepare the way, by putting the unique ID of the chip you DON'T
//  want asleep into the "StateBuffer" array.

//Start by preparing the way for a call of TMRom by the following. (bTmp is
//being used to select WHICH chip's ID will be passed to FillsiNumbersForTMRom)

//Before this call, there should be a sensible string in both sChipID[0] and
//   sChipID[1].. which SHOULD be the case, by this point, due to data vetting
//   in the eChipID OnChange handlers
bTmpL:=0;
if rbReadChip1.Checked then bTmpL:=1;
FillsiNumbersForTMRom(bTmpL);

if bErrL=0 then begin
  siResult:=TMRom(liSessionHandle,@bTMEXstatebuffer,@siNumbersForTMRom);
  //=== Anecdote... why programmers go gray....
  //31Dec13 into 1/1/14: I had "@FillsiNumbersForTMRom"... the address
  //     of the subroutine, rather than "@siNumbersForTMRom"... the address
  //     of the array. Took several hours to spot my mistake, mere
  //     seconds to remove. Sigh.

  //TMRom returns 1 if all well

  if siResult=-1 then begin
      bErrL:=50;
      bErrL1:=1;
      sErrMsgL:='PORT_NOT_INITIALIZED - Specified MicroLan has not '+
                 'been initialized with a call to the TMSetup function.';
      end;//siResult=-1
  if siResult=-2 then begin
      bErrL:=51;
      bErrL1:=2;
      sErrMsgL:='PORT_NOT_EXIST - Specified MicroLan nonexistent.';
      end;//siResult=-2
  if siResult=-3 then begin
      bErrL:=52;
      bErrL1:=3;
      sErrMsgL:='NO_SUCH_FUNCTION - Function not supported.';
      end;//siResult=-3
  if siResult=-200 then begin
      bErrL:=53;
      bErrL1:=200;
      sErrMsgL:='INVALID_SESSION - session not valid (not applicable in DOS TMEX)';
      end;//siResult=-200
  if siResult=-201 then begin
      bErrL:=54;
      bErrL1:=201;
      sErrMsgL:='HS_NOT_FOUND - Hardware_Specific driver not found and is required.';
      end;//siResult=-201
   //Now check that it wasn't an un-provided for error...
   if (bErrL=0) and (siResult<>1) then begin//TMRom returns 1 when all well
      bErrL:=56;
      bErrL1:=99;
      sErrMsgL:='TMRom returned an undocumented error flag: '+inttostr(siResult);
      end;//siResult=-201

      //end of taking care of error messages

   end;//End of first part of telling all but one of them to go to sleep


//Now that we've prepared the way, by putting the chip ID
//  of the chip we want left awake into the right part of
//  bTMEXstatebuffer, it is time for the TMAccess call...

if bErrL=0 then begin
  siResult:=TMStrongAccess(liSessionHandle,@bTMEXstatebuffer);
  //Returns 1 if all well: chip seen on MicroLan, and the chip awake
  //   while others sleep... "ROM" (the chip) "selected" in Dallas-speak

  //You have a choice here. You can use TMStrongAccess or TMAccess.
  //They both need the same parameters.
  //They both put all of the chips but one to sleep.
  //The error codes they return are ALMOST the same... the only
  //  difference being that with TMStrongAccess, if zero returned
  //  it means that the chip requested wasn't seen.
  //With TMAccess, if zero is returned it means that no chips were
  //  seen (at least nothing sent a "presence" pulse.
  //The downside of TMStrongAccess is that it takes three times as
  //  long to execute as TMAccess. For the extra security of knowing
  //  that the chip you expected to be there was found, I say the
  //  time is usually well spent!

  //Case of a zero returned taken care of at bottom

  if siResult=-1 then begin
      bErrL:=60;
      bErrL1:=1;
      sErrMsgL:='PORT_NOT_INITIALIZED - Specified MicroLan has not '+
                 'been initialized with a call to the TMSetup function.';
      end;//siResult=-1
  if siResult=-2 then begin
      bErrL:=61;
      bErrL1:=2;
      sErrMsgL:='PORT_NOT_EXIST - Specified MicroLan nonexistent.';
      end;//siResult=-2
  if siResult=-3 then begin
      bErrL:=62;
      bErrL1:=3;
      sErrMsgL:='NO_SUCH_FUNCTION - Function not supported.';
      end;//siResult=-3
  if siResult=-200 then begin
      bErrL:=63;
      bErrL1:=200;
      sErrMsgL:='INVALID_SESSION - session not valid (not applicable in DOS TMEX)';
      end;//siResult=-200
  if siResult=-201 then begin
      bErrL:=64;
      bErrL1:=201;
      sErrMsgL:='HS_NOT_FOUND - Hardware_Specific driver not found and is required.';
      end;//siResult=-201
  if siResult=0 then begin
      bErrL:=65;
      bErrL1:=0;
      sErrMsgL:='Chip not detected when TMStrongAccess tried to select';
      end;//siResult=0

  //Now check that it wasn't an un-provided-for error...
  if (bErrL=0) and
     (siResult<>1) and  //1 is what is returned when all well!
     (siResult<>0) then begin
      bErrL:=66;
      bErrL1:=99;
      sErrMsgL:='TMRom returned an undocumented error flag: '+inttostr(siResult);
      end;//siResult=-201

      //end taking care of error messages
  //showmessage(inttostr(siResult));

   end;//End of second part of telling all but one of them to go to sleep


//===CCCCC================================================
==
//Consider doing things with the one chip that is awake
//N.B. This is the part of TalkTo1Wire where the "customizing"
//  occurs, to deal with different jobs, different chips.
//WHAT is done with the chip is determined by the value in wWhatAction

if bErrL=0 then begin//1
boWhatActionHandlerFound:=false;

//Do things with the chip which is not asleep...

//The "do it"s in this "Do things" block, selected by
//   wWhichAction, may be large, may
//   have multiple steps. Will be chip specific
//   (with some common themes.)

//If, say, reading from a sensor, postpone,
//   separate out into separate code,
//   USING the results from the sensor
//   until you are OUT of the "use MicroLan" stuff
//if (problem) then begin bErrL:=... 70-249 reserved for any reporting
                        //which may be needed in this block


//-------------------
if wWhatAction=$44 then begin //2 Issue "Convert T" and do short pause
boWhatActionHandlerFound:=true;

//KLUDGE... DS1820 code... TRIPLE CHECK, even if "works"...

//Send message to chip telling it to take a reading
siResult:=TMTouchByte(liSessionHandle,$44);

//if on parasitic, should go into strong pullup for 500ms
//  just after "Convert Tture" command issued.
//(Is there a way to know if it is on parasitic?)

KludgeDelay;
//if it was on strong pull up, should come out
//the timing of coming out of strong pull up
//  is not clear in MemoryFunctionsFlowChart...
//  shown as happening after "convert tture",
//  before the "do resets until master achieves reset

end;//2 if wWhatAction=$44 then...

//-------------------
if wWhatAction=$BE then begin //2 Read scratchpad and CS, check CS
   //There is no point in using this wWhatAction switch until after
   //  the chip concerned has been accessed previously with something
   //  like a $44 (Convert tture) command, to put something interesting
   //  into the scratchpad
boWhatActionHandlerFound:=true;

//KLUDGE... DS1820 code... TRIPLE CHECK, even if "works"...

//Now issue a "ReadScratchpad" cmnd..
//The "Master Tx reset?" in the DS1820 Memory Functions flowchart, just after
//   the "Master Rx data from scratchpad" is there to cover
//   the case of a programmer WANTING to abandon the reading of the
//   stream of 9 bytes (data + checksum byte) the DS1820 is generating.
//   There's no NEED to issue a reset, and it would only happen
//   if the programmer inserted a "do reset" into the design of the program.
siResult:=TMTouchByte(liSessionHandle,$BE);

//Read 8 bytes, throwing away last 6
siResult:=TMTouchByte(liSessionHandle,$FF);
bTtureLo:=siResult and $FF;
siResult:=TMTouchByte(liSessionHandle,$FF);
bTtureHi:=siResult and $FF;

siResult:=TMTouchByte(liSessionHandle,$FF);
siResult:=TMTouchByte(liSessionHandle,$FF);
siResult:=TMTouchByte(liSessionHandle,$FF);
siResult:=TMTouchByte(liSessionHandle,$FF);
siResult:=TMTouchByte(liSessionHandle,$FF);
siResult:=TMTouchByte(liSessionHandle,$FF);


//Get one byte checksum
siResult:=TMTouchByte(liSessionHandle,$FF);
//See if it was what it ought to be.

(*Same code fine for reading DS1820 and DS18B20...
  How the two bytes returned from the chip are interpreted has to be
  different for 1820 ($10) and 18B20 ($28)
  if (baDMLRomID[bIdx,0]=$10) then rsTmp:=rRawToC(bTmp,bTmp2);
  if (baDMLRomID[bIdx,0]=$28) then rsTmp:=rRawToC18B20(bTmp,bTmp2);
                              *)
   laRes3.caption:='The raw values from the chip were: '+
           inttostr(bTtureHi)+'  '+inttostr(bTtureLo);

   //Now convert values in bTtureLo, bTtureHi to HUNDRETHS of degrees Kelvin.
   //The Dallas chips work in Celcius, which is Kelvin +273.15 Using
   //centi-degrees K (inside the program) means that you
   //don't need the hassles of floating point numbers. (You can, of course,
   //display the ttures in any units, with a simple conversion occurring just
   //before the tture appears.)
   //Range: If a 16-bit unsigned variable is used for the tture, you can
   //express any tture from absolute zero to 655.35 Kelvin, which is about
   //382 Celcius, which will, I hope "do".

   //While both the DS1820 (family code $10) and the DS18B20 (family code $28)
   //  are "driven" the same way, you have to interpret the results differently,
   //  hence the inclusion of the chip's family code in what follows...

   bTmpL:=0;
   if rbReadChip1.Checked then bTmpL:=1;
   wTtureCentiK:=wRawTTureToCentiK(bTtureLo,bTtureHi,
                    strtoint('$'+copy(sChipID[bTmpL],15,2)));
   laTtureResult.caption:='Tture is: '+sTtureCfrmCentiK(wTtureCentiK)+' degrees C';;

end;//2 if wWhatAction=$BE then...

//Here ends block of wWhatAction handlers. Be sure that one was
//  executed for the value in wWhatAction used to call
//  TalkTo1Wire this time....

if boWhatActionHandlerFound=false then begin //2
       bErrL:=240;
       //bErrL1:= not used here
       sErrMsgL:='Un-supported wWhatAction requested: $'+inttohex(wWhatAction,4);
       showmessage(sErrMsgL);
       end;//2

end;//Do things with the chip which is not asleep...

//===AAAAA==========================
//Consider calling TMEndSession, as we are done with MicroLan,
//so now release resources, release lock on it.

//NOTE THAT THIS ONE IS SPECIAL... sometimes we do it, even if
//  errors arose along the way. We only DON'T do it when we
//  didn't succeed in opening the session, which will be indicated
//  by a value in bErrL of between 1 and 19, inclusive.

if (bErrL=0) or (bErrL>19) then begin
siResult:=TMEndSession(liSessionHandle);
//TMEX API notes said TMEndSession returns 16-bit
       //UNsigned... but then gave example where "if (it)<0 then..."
       //appeared. So I am using Delphi smallint, which is 16 bit SIGNED
if siResult<0 then begin
      bErrL:=250;//For details of error see TMEX Session Error Return Codes
          bErrL1:=240;
          if siResult=-200 then begin
             bErrL1:=200;
             sErrMsgL:='INVALID_SESSION -  session not valid';
             end;
          if siResult=-201 then begin
             bErrL1:=201;
             sErrMsgL:='HS_NOT_FOUND -  Required Hardware_Specific driver not found';
             end;
          if bErrL1=240 then begin
             bErrL1:=1;
             sErrMsgL:='Other error, not in Dallas docs, TMEX API ver 3.10';
             end;
       end;//siResult<0
       //end of flag problems code for call of TMEndSession
   end;//call TMEndSession

//Done using the MicroLan, so now we do...
if bErrL<>0 then DoWhatReportingOfErrorYouWantTo;

/// ... and....
//NOW use things we may have collected while using the MicroLan,
//   e.g. sensor readings.... if bErrL is still zero at this point.
//   (If it isn't, we can't be sure that you did collect what you
//   went to the MicroLan for.
if bErrL=0 then begin
    DoThingsIfNeeded;
    //laRes3.caption:=inttostr(bTtureLo)+'  '+inttostr(bTtureHi);
    end;

end;//TalkTo1Wire;

procedure TDS048f1.eChipID0Change(Sender: TObject);
//Yes! I realize that this routine is not well written!
var bCount:byte;
    sTmpL:string;
begin
boGoodChipID0:=true;
sChipID[0]:=eChipID0.text;
if length(eChipID0.text)<>16 then
  begin
    boGoodChipID0:=false;
    end//no ; here
  else begin
    for bCount:=1 to 16 do begin
       sTmpL:=uppercase(eChipID0.text[bCount]);
       if pos(sTmpL,'0123456789ABCDEF')=0 then boGoodChipID0:=false;
       end;//for
    end;//else
SeeIfTimeToEnableReadChip;
end;//eChipIDChange

procedure TDS048f1.eChipID1Change(Sender: TObject);
//Yes! I realise that this routine is not well written!
var bCount:byte;
    sTmpL:string;
begin
boGoodChipID1:=true;
sChipID[1]:=eChipID1.text;
if length(eChipID1.text)<>16 then
  begin
    boGoodChipID1:=false;
    end//no ; here
  else begin
    for bCount:=1 to 16 do begin
       sTmpL:=uppercase(eChipID1.text[bCount]);
       if pos(sTmpL,'0123456789ABCDEF')=0 then boGoodChipID1:=false;
       end;//for
    end;//else
SeeIfTimeToEnableReadChip;
end;//eChipIDChange

procedure TDS048f1.KludgeDelay;
var lwTmp:longword;
begin
lwTmp:=gettickcount+650;
repeat
application.processmessages;
until gettickcount>lwTmp;
end;//KludgeDelay

function TDS048f1.wRawTTureToCentiK(
     bTtureLo,bTtureHi,bChipFam:byte):word;
var wTmpL:word;
    bHths:byte;
    boNegativeL:boolean;
    liTmpL:longint;//signed 32 bit
//Returns 65535	if there's a problem
//Otherwise returns the temperature indicted by the numbers
//  from the sensor... expressed in hundreTHs of degrees Kelvin.

//This routine looks arcane... and it may have errors in it!
//However, it is "no big deal".
//All we are doing here is taking the two numbers returned by
//  a Dallas 1-Wire tture sensor, and TRYING to apply the right
//  rules to convert them to a single number, closely related
//  to units used in the everyday world for measuring temperatures.

//In: two numbers, and a chip family ID
//Out: Temperature, in centiKelvins.
//Centi-Kelvin: hundreTH of a Kelvin degree.
//Zero Celcius is 273.15 Kelvin is 27315 centiKelvins
//100  Celcius is 373.15 Kelvin is 37312 centiKelvins

//THIS CODE HAS NOT BEEN TESTED AS THOROUGHLY as the rest of this
//I (and others!) have had trouble with the code for
//this conversion in the past, with, in particular, problems
//converting values which should give negative ttures in C, and
//other special cases.

//All of the 1-Wire tture sensors work in Celsius. If you want
//Fahrenheit, you're best bet is to convert the raw bytes
//to C, and go to F from there*)

//Both the DS1820 and the DS18B20 will return 85degC if their
//tture register is read before the power-on reset value is changed.

begin
wTmpL:=65535;
if (bChipFam<>$10)and(bChipFam<>$28)then begin //1
  showmessage('wRawTTureToCentiK was sent a chip type it doesn''t know '+
  'what to do with. Will return a value of 65535');
  end; //end of deal with family code not $10 and not $28

if bChipFam=$10 then begin
//Convert bTtureLo and bTtureHi from a DS1820 to tture in centiKelvins

//This code for handling the two bytes from a DS1820,
//LSB of chip ID: $10. Examples taken from Dallas docs...
//I hope correctly... If code doesn't give these results,
//it is more likely the code that is wrong.

//In the table, the two bytes the DS1820 returns have been
//concatenated to a single 16-bit number.

//$0001 is 0.5 degree C  (27365 centidegrees K)
//$0007 is 3.5 d C       (27665 centidegrees K)
//$FFFF is -0.5 d C      (27265 centidegrees K)

//This algorithm only interprets the tture to 0.5 degree C.
//See data sheet for how to get greater resolution.

  //bTtureHi:=$0;//for debug
  //bTtureLo:=$0;//for debug

//Start by finding tture in hundreTHs of degrees Celcius

  if (bTtureLo and 1)=1 then
    bHths:=50 else bHths:=0;
  if bTtureHi=$FF then begin (*negative tture*)
    bTtureLo:=(NOT bTtureLo)+1;
    liTmpL:=(((bTtureLo div 2)*100)+bHths)*-1;
    end //no ; here. Done doing negative number
  else begin //+ve tture
    liTmpL:=((bTtureLo div 2)*100)+bHths;
  end;(*else*)

  //At this point, liTmpL holds tture in centidegrees C
  //showmessage(inttostr(liTmpL));

//Next part also used in code for DS18B20... should move to a function
//  either can call

  //Be sure we aren't headed for a tture of below
  //   absolute zero, which is 0 degrees K
  if liTmpL<-27315 then begin
    //do nothing if <-27315.. flow will fall through, with
    //wTmpL still set to rogue for "problem"
    end//no ; here
   else begin//liTmpL was >= -27315... good!
  //Convert to centidegrees C to centidegrees K... to avoid the need
  //for negative numbers... dealing in centidegrees spared us fractions
    liTmpL:=liTmpL+27315;
    end;//.. of the else for liTmpL was >= -27315

  //liTmpL:=1000;//1000 centiK= 10 deg K:= -263.15 deg C<<for debug

  wTmpL:=liTmpL;
end;//bChipFam=$10

if bChipFam=$28 then begin
//Convert bTtureLo and bTtureHi from a DS18B20 to tture in centiKelvins

//This code for handling the two bytes from a DS18B20,
//LSB of chip ID: $28. Examples taken from Dallas docs...
//I hope correctly... If code doesn't give these results,
//it is more likely the code that is wrong.

//In the table, the two bytes the DS18B20 returns have been
//concatenated to a single 16-bit number.

//$07D0 is 125.00 degrees C
//$0008 is   0.5  degree C  (27365 centidegrees K)
//$0000 is   0.000 d C      (27315 centidegrees K)
//$FFF8 is - 0.500 d C      (27265 centidegrees K)
//$FF5E is -10.125 d C
//$FC90 is -55.000 dC

//if (bTtureHi and $F8) = $F8, the number is a negative number,
//  given in two's complement form.

//The LS 4 bits give the fractional part of the tture.

//The theoretical resolution of the hardware is 1/16th degree, but
//  this algorithm doesn't provide for thousandths of degrees

  //bTtureHi:=$0;//for debug
  //bTtureLo:=$0;//for debug



//Start by finding tture in hundreTHs of degrees Celcius

//Combine MS and LS bytes in wTmpL, remembering that at
//  the end of the SR that must be 65535 if conversion has failed, something
//  else if conversion has not failed.
//Decide if the number is +ve or negative, and use if.. then.. to temporarily
//  divide flow accordingly at this point after setting boNegativeL

//For +ve number... nothing to do at this stage
//For -ve number... do two's complement

//Calculate the centidegrees Celcius, forgetting whether number had 2's complement
//Move into liTmpL (signed) and multiply by -1 if boNegativeL is true.

//Now that tture in centidegrees C is in liTmpL, convert to centidegrees K,
//  and return that to wTmpL... or, as I said at start, make it 65535
//  if conversion has failed.

wTmpL:=bTtureHi*$FF+bTtureLo;

boNegativeL:=false;
if (wTmpL and $F800)=$F800 then begin
  boNegativeL:=true;
  wTmpL:=(NOT wTmpL)+1;
  end;

//Yes... this could be done better!
bTtureLo:=wTmpL AND $0F;//re-purposed to hold fraction part.
if bTtureLo=$0 then bHths:=0;//Exactly 0
if bTtureLo=$1 then bHths:=6;//
if bTtureLo=$2 then bHths:=12;//0.125
if bTtureLo=$3 then bHths:=18;//
if bTtureLo=$4 then bHths:=25;//Exactly 0.25
if bTtureLo=$5 then bHths:=32;//
if bTtureLo=$6 then bHths:=38;//0.375
if bTtureLo=$7 then bHths:=44;//
if bTtureLo=$8 then bHths:=50;//Exactly 0.5
if bTtureLo=$9 then bHths:=56;//
if bTtureLo=$10 then bHths:=62;//0.625
if bTtureLo=$11 then bHths:=68;//
if bTtureLo=$12 then bHths:=75;//Exactly 0.75
if bTtureLo=$13 then bHths:=82;//
if bTtureLo=$14 then bHths:=88;//0.875
if bTtureLo=$15 then bHths:=94;//

liTmpL:=wTmpL;//32 bit signed
liTmpL:=(liTmpL div 16)*100;//Integer part now in centidegrees C
liTmpL:=liTmpL+bHths;//add in the previously determined 100ths.
if boNegativeL then liTmpL:=litmpL*-1;//Fully realized tture in C centidegrees
//showmessage(inttostr(liTmpL));<<for prgm testing

//Next part also used in code for DS1820... should move to a function
//  either can call

  //Be sure we aren't headed for a tture of below
  //   absolute zero, which is 0 degrees K
  if liTmpL<-27315 then begin
    //do nothing if <-27315.. flow will fall through, with
    //wTmpL still set to rogue for "problem"
    end//no ; here
   else begin//liTmpL was >= -27315... good!
  //Convert to centidegrees C to centidegrees K... to avoid the need
  //for negative numbers... dealing in centidegrees spared us fractions
    liTmpL:=liTmpL+27315;
    end;//.. of the else for liTmpL was >= -27315

  //liTmpL:=1000;//1000 centiK= 10 deg K:= -263.15 deg C<<for debug

  wTmpL:=liTmpL;


//  wTmpL:=1100;//1100 centiK= 11 deg K:= -262.15 deg C
end;//bChipFam=$10

result:=wTmpL;//Tture in centiKelvins... or 65535 on error
end; //wRawTTureToCentiK

function TDS048f1.sTtureCfrmCentiK(wTture:word):string;
//Supplied with tture in centidegrees Kelvin,
//Returns a string with that tture in Celcius

//This could be written better! But it works!

var sTmpL,sTmpL1:string;

begin
if wTture<27315 then begin //Process something that will be a negative
  wTture:=27315-wTture;
  sTmpL:=inttostr(wTture);
  if length(sTmpL)<2 then sTmpL:='0'+sTmpL;
  sTmpL1:=copy(sTmpL,1,length(sTmpL)-2)+'.'+copy(sTmpL,length(sTmpL)-1,2);
  if sTmpL1[1]='.' then sTmpL1:='0'+sTmpL1;
  sTmpL1:='-'+sTmpL1;
  end//no ; here. Negative number dealt with
 else begin
  wTture:=wTture-27315;
  sTmpL:=inttostr(wTture);
  if length(sTmpL)<2 then sTmpL:='0'+sTmpL;
  sTmpL1:=copy(sTmpL,1,length(sTmpL)-2)+'.'+copy(sTmpL,length(sTmpL)-1,2);
  if sTmpL1[1]='.' then sTmpL1:='0'+sTmpL1;
  end;//deal with tture at or above 0 deg C
result:=sTmpL1;
end;//sTtureCfrmCentiK

end.

P.S.... oops...

Ah. Oops. Sorry. After this was all "put to bed", I realized that it is in some respects incomplete.

For most of the program's execution, I have diligently covered all the bases in respect of error codes which can be returned following various TMEX calls.

I fear my concentration wavered while I was in the throes of getting section "C" working in the Phase Four version. I have failed to test the value returned in siResult in quite a few places there, failed to test siResult to see that no error is being reported.

"An exercise for the student", perhaps.

Sorry! Do you want me to fuss with that, or work on turning this into a unit which let's you call the major procedures from another program?





Search across all my sites with the Google search...

Custom Search

Or search just SheepdogGuides.com with the FreeFind tool...

   Search this site or the web          powered by FreeFind
  Site search Web search
Site Map    What's New    Search

This search merely looks for the words you enter. It won't answer "Where can I download InpOut32?"


If you visit 1&1's site from here, it helps me. They host my website, and I wouldn't put this link up for them if I wasn't happy with their service. They offer things for the beginner and the corporation.www.1and1.com icon

Ad from page's editor: Yes.. I do enjoy compiling these things for you. I hope they are helpful. However... this doesn't pay my bills!!! Sheepdog Software (tm) is supposed to help do that, so if you found this stuff useful, (and you run a Windows or MS-DOS PC) please visit my freeware and shareware page, download something, and circulate it for me? Links on your page to this page would also be appreciated!
Click here to visit editor's freeware, shareware page.

Link to Lazarus Tutorials main page
How to contact the editor of this page, Tom Boyd


Please consider contributing to the author of this site... and if you don't want to do that, at least check out his introduction to the new micro-donations system Flattr.htm....


Valid HTML 4.01 Transitional Page tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org. Mostly passes. There were two "unknown attributes" in Google+ button code. Sigh.


If this page causes a script to run, why? Because of things like Google panels, and the code for the search button. Why do I mention scripts? Be sure you know all you need to about spyware.

....... P a g e . . . E n d s .....