How to read PC87366 Temperature Sensor Data in C#

Can someone please point me in the right direction (with a code example or link to reference code) how I can access the register data for the PC87366 Temperature Sensor (TMS) values located from Offset 09h onwards i.e. temperature data (refer page 194 onwards)

Alternatively how can I access ACPI data for this chip without the use of WMI; unfortunately WMI only returns static / incorrect values for the ACPI instances.

NOTE: I am looking for direct code access options so please avoid suggest any indirect options that require the use of packages like SpeedFan, HWMonitor, etc... (i.e. I want to achieve the same result as those applications in code).

All examples accessing register information will be appreciated, e.g.:
accessing fan speed, voltages, ...

My preference is to code this in C#, but all examples including C++and vb.net are welcomed.

PC87366.pdf
LVL 3
VaughnWilliamsAsked:
Who is Participating?
 
VaughnWilliamsAuthor Commented:
OK to wrap this up;
Here's what I have found so far; finally with the help of drdobbs articles I have found my way to a working solution.

For those facing similar challenges I would recommend reading the following articles:

Building your own device driver:
--------------------------------------
http://www.drdobbs.com/architecture-and-design/184409876;jsessionid=O2UO0XHLKVV4VQE1GHPSKHWATMY32JVN?pgno=3

How to install and access the device driver from C#:
---------------------------------------------------------------
http://www.drdobbs.com/windows/184416423

I can also recommend the following Delphi based guide on how to make the giveio.sys and totalio.sys device driver less of a security concern.
------------------------------------------------------------------------------------------------
http://www.grahamwideman.com/gw/tech/Delphi/iopm/index.htm

And finally for those who prefer a low cost and painless solution (no gymnastic research and coding required) then I can suggest the following libraries:

NTPort Library ($35)
-------------------------
http://www.zealsoftstudio.com/ntport/download.html
Note: with this one you have to do all the research into what io port and offset will provide the values you require.

CPUID development Kits (starting from €1099)
--------------------------------------------------------
http://www.cpuid-pro.com/index.php
http://www.cpuid-pro.com/index.php
Note: Although more costly CPUID does do a lot of the work for you.

...and finally
I can also recommend looking into SpeedFan (it's free and really good quality)
--------------------------------------------------------------------------------------------
http://www.almico.com/speedfan.php

The solution can be configured to write the values to a CSV file (it does this every +-3 seconds); you can then access this file to retrieve the value for use in your application (it does however mean that you have a dependency on a 3rd party application)
0
 
Bob LearnedCommented:
While I don't have a ready answer, I believe that this question has some interest for me.  I believe that there should be some kind of Power Management API that should provide you that information.  What operating systems are you working with?
0
 
VaughnWilliamsAuthor Commented:
XP and Vista (intel processors)

Some Additional info:
-------------------------
So far I have been able to confirm that due to restrictions the WMI temperature is by design not working (i.e. Microsoft state that the CurrentReading value is broken by design) http://support.microsoft.com/kb/306852

From the package perspective, it appears:
 - Speedfan makes use of a custom built device driver (speedfan.sys) to access this data
 - CPUID's HWMonitor however seems to get at this information without any driver? Now if only I could figure out how, suspected it's either through an existing device driver or via ACPI. They also offer a development suite, but for the moment I would prefer to avoid the need to purchase anything (even to the point of developing a custom driver)

Haven't seen anything related to the Power Management API, but I willing to try anything.

Another alternative approach I'm willing to consider is a non licensed solution that records the values to a log file that I could access (not sure if a non commercial solution exists)

0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
VaughnWilliamsAuthor Commented:
Correction; it appears that HWMonitor is using also using a driver (giveio.sys), same approach previous followed by the retired MBM (motherboard monitor)

How this is achieved is what I'd like to know; hope someone can fill me in (e.g. how to interact with giveio.sys in C# to retrieve the temperature data).
0
 
Bob LearnedCommented:
I believe that it is important to know what operating systems are you working with?
0
 
VaughnWilliamsAuthor Commented:
XP and Vista?
0
 
Bob LearnedCommented:
Did you say anything about CPUID (PC Wizard)?

http://www.cpuid.com/pcwizard.php

"Sensor : NSC PC87365/PC87366"
0
 
VaughnWilliamsAuthor Commented:
Unfortunately yes I did mention CPUID (as HWMonitor), this is a commercial solution, something I was hoping to avoid.

My research has taken me a little further with the following article (source document of giveio.sys and totalio.sys):
http://www.drdobbs.com/architecture-and-design/184409876;jsessionid=O2UO0XHLKVV4VQE1GHPSKHWATMY32JVN?pgno=3

Basically from NT onwards direct access to ports / IO was prohibited; to access this a driver must be developed used.

In my case I would use giveio source as the base, from which I will allow only port specific access, as mentioned in the following article:
http://www.grahamwideman.com/gw/tech/Delphi/iopm/index.htm

What still perturbs me is exactly how to communicate with the driver in c#; so I'd appreciate if there's anyone who has examples of driver communication in c#.

0
 
Bob LearnedCommented:
PC Wizard is freeware, and I don't know anything about HWMonitor.  I did fint out that the PC87365 does comply with ACPI specifications, but I haven't found any resource that talks about the exact commands.
0
 
VaughnWilliamsAuthor Commented:
HWMonitor and PC Wizard are both products of CPUID; Difference in respect of temperature is as follows:
 - PC Wizard data is based on ACPI; or more specifically the same data that is accessible from WMI. As mentioned in the Microsoft note: the values are broken by design.
 - HWMonitor on the other hand (similarly to SpeedFan) gains access to real values directly from the PC87366 chip controlling.

Simple test is to block off the ventilation to the PC; and see if the values returned change. With both HW Monitor and SpeedFan the changes is immediately evident, whereas with WMI and PC Wizard, no change is visible.

Basically I need an explanation of how to communicate with the giveio.sys  driver in c#.
0
 
Bob LearnedCommented:
That would be a great trick, but one that I don't believe that I can pull off unfortunately--it was worth a shot to me...
0
 
Bob LearnedCommented:
That is much better than I was able to find.  Granted, it was not my first priority, so it was probably faster for you to find a solution.  I would like to see some code that specifically addresses this situation, from the Dr. Dobbs article--which is a great resource!!
0
 
VaughnWilliamsAuthor Commented:
The 1st Dr Dobbs articles provides the source code and explanation for giveio.sys and totalio.sys; if you don't have either the Microsoft driver sdk or visual c++ available then I would suggest downloading one of the many precompiled giveio.sys drivers (google is your friend)

Then the code presented in the second Dr Dobbs articles shows you exactly how to work with the driver. You need to navigate away from the main page for a full set of code, for example Click on Page 6 (Example 3) --> how to get data from the driver.

I also found the examples in Delphi article very useful for examples on how to modify giveio.sys to control which ports are exposed by your custom driver (remember giveio.sys exposes everything, and is only useful for testing).
Also look at the Delphi article for Porttest, good example on how to develop an application to view a range of values.
0
 
Bob LearnedCommented:
Thank you!!  Google is only my friend when I can find what I need to find--the magic is coming up with just the right search expression.  Otherwise, you waste a lot of time digging through a lot of irrelevant stuff.
0
 
Bob LearnedCommented:
The "Accessing Device Drivers from C#" spreads the code out among all the pages.  Is there a link to download all the code as one file?
0
 
VaughnWilliamsAuthor Commented:
Unfortunately not, but as a second best option I will attach the extraction I did into a word docx (yes it was done the painful way, page by page)

Hopefully this saves some of the hair pulling...
Accessing-Device-Drivers-from-C.docx
0
 
Bob LearnedCommented:
I see a lot of code fragments, but I still fail to see a coherent set of unsafe native methods that will get you what you need.  I think that the real fun comes in figuring out what the article is talking about, enough to build something useful, which is my goal.
0
 
VaughnWilliamsAuthor Commented:
As I said it saves some of the hair pulling; the end result in my case was worth it, fortunately for me I only had one chip type to deal with; the search for the document on the PC87366 chip was a mission all unto itself...

Something else I came to find in my travels is one area where WMI does at least work reliably; accessing SMART data for the hard disks.
Attached for completeness of this question is an example of the code for getting the temperature value for a few hard drive manufacturers. Hopefully it's also of help to someone.

0
 
VaughnWilliamsAuthor Commented:
Code for reading SMART HD temperature from WMI
string myTemperature = string.Empty;
string myTempResult = string.Empty;
bool myDiskVendorFound = false;

ManagementObjectSearcher mySearcher = new ManagementObjectSearcher("root\\WMI", "SELECT * FROM MSStorageDriver_ATAPISmartData");
ManagementObjectSearcher myLogicalDisk = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");

foreach (ManagementObject myQueryObjDisk in myLogicalDisk.Get()) {
	string DiskName = Convert.ToString(myQueryObjDisk("Model"));
	foreach (ManagementObject myQueryObjSearch in mySearcher.Get()) {
		//Only process 1st physical drive
		if (myDiskVendorFound == false) {
			Byte[] arrVendorSpecific = (Byte[])(myQueryObjSearch("VendorSpecific"));
			if (DiskName.ToUpper.IndexOf("Maxtor".ToUpper) >= 0) {
				myTemperature = Convert.ToString(arrVendorSpecific(151));
				myTempResult = (DiskName + " ") + myTemperature + "°C" + " Maxtor";
				Console.WriteLine(myTemperature);
				myDiskVendorFound = true;
			}
			else if ((DiskName.ToUpper.IndexOf("Western Digital".ToUpper) >= 0) || (DiskName.ToUpper.IndexOf("WesternDigital".ToUpper) >= 0) || (DiskName.ToUpper.IndexOf("WD".ToUpper) >= 0)) {
				myTemperature = Convert.ToString(arrVendorSpecific(139));
				myTempResult = (DiskName + " ") + myTemperature + "°C" + " Western Digital";
				Console.WriteLine(myTemperature);
				myDiskVendorFound = true;
			}
			else if ((DiskName.ToUpper.IndexOf("Seagate".ToUpper) >= 0) || (DiskName.ToUpper.IndexOf("ST".ToUpper) >= 0) || (DiskName.ToUpper.IndexOf("Seagate Technology".ToUpper) >= 0)) {
				myTemperature = Convert.ToString(arrVendorSpecific(127));
				myTempResult = (DiskName + " ") + myTemperature + "°C" + " Seagate";
				Console.WriteLine(myTemperature);
				myDiskVendorFound = true;
			}
			else if (DiskName.ToUpper.IndexOf("Fujitsu".ToUpper) >= 0) {
				myTemperature = Convert.ToString(arrVendorSpecific(151));
				myTempResult = (DiskName + " ") + myTemperature + "°C" + " Fujitsu";
				Console.WriteLine(myTemperature);
				myDiskVendorFound = true;
			}
			else if (DiskName.ToUpper.IndexOf("Samsung".ToUpper) >= 0) {
				myTemperature = Convert.ToString(arrVendorSpecific(135));
				myTempResult = (DiskName + " ") + myTemperature + "°C" + " Samsung";
				Console.WriteLine(myTemperature);
				myDiskVendorFound = true;
			}
			else if (DiskName.ToUpper.IndexOf("IBM".ToUpper) >= 0) {
				myTemperature = Convert.ToString(arrVendorSpecific(139));
				myTempResult = (DiskName + " ") + myTemperature + "°C" + " IBM";
				Console.WriteLine(myTemperature);
				myDiskVendorFound = true;
			}
			else if (DiskName.ToUpper.IndexOf("HITACHI".ToUpper) >= 0) {
				myTemperature = Convert.ToString(arrVendorSpecific(151));
				myTempResult = (DiskName + " ") + myTemperature + "°C" + " HITACHI SD";
				Console.WriteLine(myTemperature);
				myDiskVendorFound = true;
			}
			else {
				//Send -99 if hard drive type is not found
				Console.WriteLine(-99);
				myDiskVendorFound = true;
			}
		}
	}
}

Open in new window

0
 
Bob LearnedCommented:
I do have the WMI query for S.M.A.R.T. drives, but I was really interested in finding a solution to a question that I couldn't answer *BIG GRIN*.  I don't have much hair left, so I was hoping that you were willing to share the code that you found.
0
 
VaughnWilliamsAuthor Commented:
Ok let make this a little easier, but not too easy... ;-)

Getting Permission From NT
----------------------------------------------------------
Under NT, "user-mode" code (ie: applications written by mere mortals) is not allowed to access hardware directly, hence when your application attempts to execute an I/O instruction you get an exception.  The idea is, of course, that hardware resources are things that no application should just take over at will, instead it should be up to the operating system (and its drivers) to arbitrate between different apps requests to use those resources.

That's the theory.  Turns out that the NT kernel maintains a map of I/O port addresses that each process is allowed to access, and for your apps that's normally set to "none". But we can tell NT to use a different I/O Permissions Map (IOPM) for our process and thereby gain access to the ports.  This approach is of course very naughty from a disciplined OS standpoint, so not recommended for widely distributed commercial apps.  But for those times when you just need to hack on some hardware, who has time to write a proper NT device driver?

The only problem is that user-mode code is not allowed to execute the kernel functions to change the permissions map. The workaround for that problem is to create an NT driver (drivers have sufficient privileges) to twiddle the IOPM at the request of your app. Just such a driver, giveio.sys, has been floating around the net since '96, authored by Dale Roberts in conjunction with a May 96 Dr Dobbs article.
----------------------------------------------------------

Basically you need to use a driver like giveio.sys and totalio.sys to authorise your C# program for direct IO access. This is done through the methods described in the  "How to install and access the device driver from C#" article, or more specifically this code section:


     hFileHandle = Win32Methods.CreateFile("\\\\.\\MyDriver",
              Win32Methods.GENERIC_READ | Win32Methods.GENERIC_WRITE,
              0, (IntPtr) 0, Win32Methods.OPEN_EXISTING,0,Win32Methods.NULL);


Then you need as you assumed correctly "unsafe native methods"; look here for clues: http://answers.yahoo.com/question/index?qid=20080404094933AA4dipY
Yahoo being our "friend" in this case...

Well I hope that helps, from here on in you pretty much have to know which addresses relate to what registers, that where the PC87366 manual came in handy for me.
0
 
VaughnWilliamsAuthor Commented:
BTW the extraction "Getting Permission From NT" came from Graham Wideman if you'd like to read more.
http://www.grahamwideman.com/gw/tech/Delphi/iopm/index.htm
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.