Problem with access to shared memory(W2K) / ORIGINALLY (win32) speedfan api control

T

Thomas Heller

Claudio Grondi said:
Background information:
---------------------------------
in order to monitor mainboard sensory data
as fan speeds, temperatures, applications
like SpeedFan http://www.almico.com/speedfan.php
or MBM http://mbm.livewiredev.com/
can be used.
Both of the mentioned apps expose data got
from the hardware in a shared memory area.

The goal to achieve:
---------------------------
is to supervise the motherboard sensory
data from within a Python script

The approach:

For the mistake you made see below, hope that helps.

For the general way to solve this problem you should know that you can
access a shared memory area with a certain name also with Python's mmap
module, although that is probably not documented very good. There was a
recipe posted a few days ago which showed different ways to acces shared
memory, with or without ctypes.
The problem:
-----------------
the below listed script code returns
always same values, what
leads to the conclusion, that something
is going wrong.

Can anyone help?

Thanks in advance

Claudio

The code
-------------
I use is provided also here:
http://www.codecomments.com/Python/message430495.html
http://mail.python.org/pipermail/python-list/2005-March/271853.html
(the mmap part of it doesn't work at all)

from ctypes import *

class Buffer(Structure):
# just to see if any useful data can be acquired
_fields_ = [
("Data0", c_longlong)
,("Data1", c_longlong)
,("Data2", c_longlong)
,("Data3", c_longlong)
,("Data4", c_longlong)
,("Data5", c_longlong)
,("Data6", c_longlong)
,("Data7", c_longlong)
,("Data8", c_longlong)
,("Data9", c_longlong)
,("DataA", c_longlong)
,("DataB", c_longlong)
,("DataC", c_longlong)
,("DataD", c_longlong)
,("DataE", c_longlong)
,("DataF", c_longlong)
]

szName = c_char_p("SFSharedMemory_ALM") # SpeedFan
szName = c_char_p("$M$B$M$5$S$D$") # MBM
# szName = c_char_p("blabla") # not existing shared memory

FILE_MAP_ALL_ACCESS = 0xF001F
FALSE = 0

hMapObject = windll.kernel32.OpenFileMappingA(
FILE_MAP_ALL_ACCESS
,FALSE
,szName
)
if (hMapObject == 0):
print "Could not open file mapping object"
raise WinError()

pBuf = windll.kernel32.MapViewOfFile(
hMapObject
,FILE_MAP_ALL_ACCESS
,0
,0
,0
)

if (pBuf == 0):
print "Could not map view of file"
raise WinError()
else:
print repr(pBuf)
print repr(hMapObject)

pBuf_str = cast(pBuf, c_char_p)
print repr(pBuf_str.value)
print repr(pBuf_str)

pBuf_buf = cast(pBuf, Buffer)
Here's the problem. pBuf is a pointer to a Buffer structure, not the
buffer structure itself.
Something like
pBuf_buf = Buffer.from_address(pBuf)
may work.

Thomas
 
C

Claudio Grondi

Background information:
---------------------------------
in order to monitor mainboard sensory data
as fan speeds, temperatures, applications
like SpeedFan http://www.almico.com/speedfan.php
or MBM http://mbm.livewiredev.com/
can be used.
Both of the mentioned apps expose data got
from the hardware in a shared memory area.

The goal to achieve:
---------------------------
is to supervise the motherboard sensory
data from within a Python script

The approach:
-------------------
access to the shared memory area
exposed by motherboard hardware
querying apps from Python script.

The problem:
-----------------
the below listed script code returns
always same values, what
leads to the conclusion, that something
is going wrong.

Can anyone help?

Thanks in advance

Claudio

The code
-------------
I use is provided also here:
http://www.codecomments.com/Python/message430495.html
http://mail.python.org/pipermail/python-list/2005-March/271853.html
(the mmap part of it doesn't work at all)

from ctypes import *

class Buffer(Structure):
# just to see if any useful data can be acquired
_fields_ = [
("Data0", c_longlong)
,("Data1", c_longlong)
,("Data2", c_longlong)
,("Data3", c_longlong)
,("Data4", c_longlong)
,("Data5", c_longlong)
,("Data6", c_longlong)
,("Data7", c_longlong)
,("Data8", c_longlong)
,("Data9", c_longlong)
,("DataA", c_longlong)
,("DataB", c_longlong)
,("DataC", c_longlong)
,("DataD", c_longlong)
,("DataE", c_longlong)
,("DataF", c_longlong)
]

szName = c_char_p("SFSharedMemory_ALM") # SpeedFan
szName = c_char_p("$M$B$M$5$S$D$") # MBM
# szName = c_char_p("blabla") # not existing shared memory

FILE_MAP_ALL_ACCESS = 0xF001F
FALSE = 0

hMapObject = windll.kernel32.OpenFileMappingA(
FILE_MAP_ALL_ACCESS
,FALSE
,szName
)
if (hMapObject == 0):
print "Could not open file mapping object"
raise WinError()

pBuf = windll.kernel32.MapViewOfFile(
hMapObject
,FILE_MAP_ALL_ACCESS
,0
,0
,0
)

if (pBuf == 0):
print "Could not map view of file"
raise WinError()
else:
print repr(pBuf)
print repr(hMapObject)

pBuf_str = cast(pBuf, c_char_p)
print repr(pBuf_str.value)
print repr(pBuf_str)

pBuf_buf = cast(pBuf, Buffer)
print
print
print repr(pBuf_buf)
print
print repr(pBuf_buf.Data0)
print repr(pBuf_buf.Data1)
print repr(pBuf_buf.Data2)
print repr(pBuf_buf.Data3)
print repr(pBuf_buf.Data4)
print repr(pBuf_buf.Data5)
print repr(pBuf_buf.Data6)
print repr(pBuf_buf.Data7)
print repr(pBuf_buf.Data8)
print repr(pBuf_buf.Data9)
print repr(pBuf_buf.DataA)
print repr(pBuf_buf.DataB)
print repr(pBuf_buf.DataC)
print repr(pBuf_buf.DataD)
print repr(pBuf_buf.DataE)
print repr(pBuf_buf.DataF)
#:if/else (pBuf == 0)

windll.kernel32.UnmapViewOfFile(pBuf)
windll.kernel32.CloseHandle(hMapObject)

The output
--------------
is always the same:

13107200
80
''
c_char_p('')


<__main__.Buffer object at 0x007E3570>

13107200L
0L
0L
0L
0L
0L
0L
0L
0L
0L
0L
0L
0L
0L
0L
0L
 
T

Thomas Heller

Claudio Grondi said:
It doesn't.

If I currently understand it right, cast() should
do exactly this, i.e. should write the content
pointed to by pBuf to a Python variable
pBuf_buf which is an object of the Buffer
class, where I can access the single
components like any other Python
variables - am I right or wrong?

You are right - my bad.
pBuf is a pointer to your structure, so:

ptr = cast(pBuf, POINTER(Buffer))
print ptr # should print <ctypes.LP_Buffer object at ...>
struct = ptr[0]

and now 'struct' should contain the data that you need.
For the general way to solve this problem you should know that you can
access a shared memory area with a certain name also with Python's mmap
module, although that is probably not documented very good. There was a
recipe posted a few days ago which showed different ways to acces shared
memory, with or without ctypes.

So I am already using the recipe, right?
But it doesn't work as expected.
mmap doesn't work at all failing in
shmem = mmap.mmap(0, 0, "$M$B$M$5$S$D$", mmap.ACCESS_READ)
with WindowsError: [Errno 87] wrong parameter

I get this error when I try to open a non-existing shared memory block.
From the mmap docs:

If length is 0, the maximum length of the map is the current size of
the file, except that if the file is empty Windows raises an exception
(you cannot create an empty mapping on Windows).

If I run it with non-zero length it does not raise an exception

shmem = mmap.mmap(0, 0, "$M$B$M$5$S$D$", mmap.ACCESS_READ)

although it *creates* the shared memory block, IIUC. Are you sure your
speedfan app is running when you get the WindowsError?

Thomas
 
C

Claudio Grondi

For the mistake you made see below, hope that helps.
It doesn't.
Here's the problem. pBuf is a pointer to a Buffer structure, not the
buffer structure itself.
Something like
pBuf_buf = Buffer.from_address(pBuf)
may work.
If I currently understand it right, cast() should
do exactly this, i.e. should write the content
pointed to by pBuf to a Python variable
pBuf_buf which is an object of the Buffer
class, where I can access the single
components like any other Python
variables - am I right or wrong?

How can I access content at any
real memory address in Python
like you suggest with the
fictive(?) .from_address(memPointer)
method?
Wouldn't it be anyway protected?
Is not cast() a kind of solution to this
problem?

Because the exepected buffer
contains zero bytes I can't use
cast(pBuf, c_char_p) to get the entire
content as it is done in the recipe
provided by Srijit Kumar Bhadra.
At least the .Data0 value is set by cast()
in my trials, but it seems, that this has
nothing to do with the shared memory
area content.
For the general way to solve this problem you should know that you can
access a shared memory area with a certain name also with Python's mmap
module, although that is probably not documented very good. There was a
recipe posted a few days ago which showed different ways to acces shared
memory, with or without ctypes.

So I am already using the recipe, right?
But it doesn't work as expected.
mmap doesn't work at all failing in
shmem = mmap.mmap(0, 0, "$M$B$M$5$S$D$", mmap.ACCESS_READ)
with WindowsError: [Errno 87] wrong parameter

I am on Windows 2000 SP 4, Pyhon version 2.3.5
using ctypes version 0.9.5 .

Any further hints?

Claudio
 
C

Claudio Grondi

Thomas Heller,
it seems, that your email address
(e-mail address removed) doesn't work
or at least don't accept attachments,
so maybe you can provide me with
another one?
ptr = cast(pBuf, POINTER(Buffer))
print ptr # should print <ctypes.LP_Buffer object at ...>
struct = ptr[0]

results in breakdown of Python
(Windows exception, can't read from memory
at 0x0...07)
due to existance of
ptr = cast(pBuf, POINTER(Buffer)) but the print
print ptr # should print <ctypes.LP_Buffer object at ...>
does its output to the console...

Strange...

Claudio

Thomas Heller said:
Claudio Grondi said:
It doesn't.

If I currently understand it right, cast() should
do exactly this, i.e. should write the content
pointed to by pBuf to a Python variable
pBuf_buf which is an object of the Buffer
class, where I can access the single
components like any other Python
variables - am I right or wrong?

You are right - my bad.
pBuf is a pointer to your structure, so:

ptr = cast(pBuf, POINTER(Buffer))
print ptr # should print <ctypes.LP_Buffer object at ...>
struct = ptr[0]

and now 'struct' should contain the data that you need.
For the general way to solve this problem you should know that you can
access a shared memory area with a certain name also with Python's mmap
module, although that is probably not documented very good. There was a
recipe posted a few days ago which showed different ways to acces shared
memory, with or without ctypes.

So I am already using the recipe, right?
But it doesn't work as expected.
mmap doesn't work at all failing in
shmem = mmap.mmap(0, 0, "$M$B$M$5$S$D$", mmap.ACCESS_READ)
with WindowsError: [Errno 87] wrong parameter

I get this error when I try to open a non-existing shared memory block.
From the mmap docs:

If length is 0, the maximum length of the map is the current size of
the file, except that if the file is empty Windows raises an exception
(you cannot create an empty mapping on Windows).

If I run it with non-zero length it does not raise an exception

shmem = mmap.mmap(0, 0, "$M$B$M$5$S$D$", mmap.ACCESS_READ)

although it *creates* the shared memory block, IIUC. Are you sure your
speedfan app is running when you get the WindowsError?

Thomas
 
C

Claudio Grondi

I have got a solution to my problem from Thomas Heller by email.

The problem was solved by using .from_address() instead of
causing trouble cast() - here the solution as a generalized
example of code for reading access to shared memory area
with given 'appropriateName':

from ctypes import *
FILE_MAP_READ = 2

strNameOfSharedMemoryAreaToAccess = 'appropriateName'

handle = windll.kernel32.OpenFileMappingA(
FILE_MAP_READ
, 0
, strNameOfSharedMemoryAreaToAccess
)
if not handle:
raise WinError()

addr = windll.kernel32.MapViewOfFile(
handle
,FILE_MAP_READ
,0
,0
,0
)
if not addr:
raise WinError()

class structureOfSharedMemoryArea(Structure):
_fields_ = [
("Elem01" , c_short ) # or any other ctype or ctype structure
("Elem02" , c_long )
...
("ElemNN" , c_long )
]

contentOfSharedMemoryArea = structureOfSharedMemoryArea.from_address(addr)

print 'Elem01 ', contentOfSharedMemoryArea.Elem01
print 'Elem02 ', contentOfSharedMemoryArea.Elem02
....
print 'ElemNN ', contentOfSharedMemoryArea.ElemNN

Claudio
 
C

Claudio Grondi

Supervising motherboard sensory data as
fan speeds or CPU and board temperatures
in Python can be done with help of the MBM 5
utility available at http://mbm.livewiredev.com/.

This utility exposes data got from the hardware
sensors in a shared memory area for querying
by another applications.

The pyMBM.py script provided below prints
excerpts of the content of the by MBM 5
in shared memory area provided data
and can be used as a starting point
for writing own scripts which need to
query motherboard sensory data or
as inspiration for creating an
appropriate pyMBM Python module.

Claudio Grondi

print
print ' pyMBM.py ver. 0.10 2005-04-08 '
print '*** ************************************************ ***'
print '*** THIS code accesses shared memory area exposed by ***'
print '*** MBM 5 (MotherBoard Monitor) ***'
print '*** install and run MBM 5 before using this script ***'
print '*** MBM 5 home: http://mbm.livewiredev.com ***'
print '*** Port of the MBM API to Python by Claudio Grondi ***'
print '*** http://www.python.org/moin/ClaudioGrondi ***'
print '*** ************************************************ ***'

# centralized settings for portability and upgradability
SENSOR_INDEX_LENGTH = 10
SENSOR_INFO_LENGTH = 100

SENSOR_NAME_LEN = 12
TIME_STRING_LENGTH = 41
MBM_PATHNAME_LENGTH = 256

SMBUSNAME_STRING_LENGTH = 41

PADDING1_SIZE_BYTES = 3
PADDING2_SIZE_BYTES = 4
PADDING3_SIZE_BYTES = 8

#define BT_ISA "type_isa"
#define BT_SMBUS "type_smbus"
#define BT_VIA686ABUS "type_via686abus"
#define BT_DIRECTIO "type_directio"
#define BT_UNKNOWN "type_unknown"
# typedef enum { btISA = 0, btSMBus, btVIA686ABus, btDirectIO } bus_t;
bus_t = [
"ISA " # 0
,"SMBus " # 1
,"Via686aBus" # 2
,"DirectIO " # 3
]

#define SMBT_INTEL "type_intel"
#define SMBT_AMD "type_amd"
#define SMBT_ALI "type_ali"
#define SMBT_NFORCE "type_nforce"
#define SMBT_SIS "type_sis"
#define SMBT_UNK BT_UNKNOWN
# typedef enum { smtSMBIntel = 0, smtSMBAMD, smtSMBALi, smtSMBNForce,
smtSMBSIS } smb_t;
smb_t = [
"Intel " # 0
,"AMD " # 1
,"Ali " # 2
,"nForce" # 3
,"sis " # 4
]

#define ST_UNKNOWN BT_UNKNOWN
#define ST_TEMPERATURE "type_temperature"
#define ST_VOLTAGE "type_voltage"
#define ST_FAN "type_fan"
#define ST_MHZ "type_mhz"
#define ST_PERCENTAGE "type_percentage"
# typedef enum { stUnknown = 0, stTemperature, stVoltage, stFan, stMhz,
stPercentage } sensor_t;
sensor_t = [
"unknown " # 0
,"temperature" # 1
,"voltage " # 2
,"fan " # 3
,"mhz " # 4
,"percentage " # 5
]

from ctypes import *

class index(Structure):
_fields_ = [
("_type" , c_int ) # type of sensor
,("_count" , c_int ) # number of sensor for that type
]
class sensor(Structure):
_fields_ = [
("_type" , c_ubyte ) # type of sensor
,("_name" , c_ubyte * SENSOR_NAME_LEN ) # name of sensor
,("_padding1", c_ubyte * PADDING1_SIZE_BYTES ) # padding of 3 byte
,("_current" , c_double ) # current value
,("_low" , c_double ) # lowest readout
,("_high" , c_double ) # highest readout
,("_readout" , c_long ) # total number of readout
,("_padding2", c_ubyte * PADDING2_SIZE_BYTES ) # padding of 4 byte
,("_total" , c_double ) # actual a long double - total amout of
all readouts
,("_padding3", c_ubyte * PADDING3_SIZE_BYTES ) # padding of 6 byte
,("_alarm1" , c_double ) # temp & fan: low alarm; voltage: % off;
,("_alarm2" , c_double ) # temp: high alarm
]
class info(Structure):
_fields_ = [
("_smbBase" , c_short ) # SMBus base address
,("_smbType" , c_ubyte ) # bus_t variant of SMBus/Isa bus used to
access chip
# typedef enum
{btISA=0,btSMBus,btVIA686ABus,btDirectIO} bus_t;
,("_smbCode" , c_ubyte ) # smb_t variant of SMBus sub type, Intel,
AMD or ALi
# typedef enum
{smtSMBIntel=0,smtSMBAMD,smtSMBALi,smtSMBNForce,smtSMBSIS} smb_t;
,("_smbAddr" , c_ubyte ) # Address of sensor chip on SMBus
,("_smbName" , c_ubyte * SMBUSNAME_STRING_LENGTH ) # Nice name for
SMBus
,("_isaBase" , c_short ) # ISA base address of sensor chip on ISA
,("_chipType" , c_int ) # Chip nr, connects with Chipinfo.ini
,("_voltageSubType", c_ubyte ) # Subvoltage option selected
]
class data_t(Structure):
_fields_ = [
("_version", c_double ) # version number (example:
51090)
,("_index" , index * SENSOR_INDEX_LENGTH ) # Sensor index
,("_sensor" , sensor * SENSOR_INFO_LENGTH ) # sensor info
,("_info" , info ) # misc. info
,("_start" , c_ubyte * TIME_STRING_LENGTH ) # start time,
TIME_STRING_LENGTH = 41
,("_current", c_ubyte * TIME_STRING_LENGTH ) # current time
,("_path" , c_ubyte * MBM_PATHNAME_LENGTH ) # MBM path
]

FILE_MAP_READ = 2
strNameOfSharedMemoryAreaToAccess = "$M$B$M$5$S$D$"

handle = windll.kernel32.OpenFileMappingA(FILE_MAP_READ, 0,
strNameOfSharedMemoryAreaToAccess)
if not handle:
raise WinError()
addr = windll.kernel32.MapViewOfFile(
handle
,FILE_MAP_READ
,0
,0
,0
)
if not addr:
raise WinError()
obj_data_t = data_t.from_address(addr)

# obj_data_t holds the entire shared memory area content which can be
accessed
# now from within Python code like it is done below:

if(__name__ == '__main__'):
print
print '_version ', obj_data_t._version
print

# print '_index ', obj_data_t._index
itemCounter = 0
for item in obj_data_t._index:
itemCounter += 1
print '_index[%2i]._type ='%itemCounter, sensor_t[item._type],
'_index._count =',repr(item._count)
print

# print '_sensor ', obj_data_t._sensor
itemCounter = 0
for item in obj_data_t._sensor:
itemCounter += 1
print '_sensor[%3i]._type ='%itemCounter, sensor_t[item._type],
strSensorName = ''
for subitem in item._name:
strSensorName += chr(subitem)
print ' ._name =', strSensorName,
print ' ._current = %7.2f'%item._current, ' ._low = %7.2f'%item._low,
' ._high = %7.2f'%item._high
print
# print '_info ', obj_data_t._info
print '_info._smbType =', bus_t[obj_data_t._info._smbType]
print '_info._smbCode =', smb_t[obj_data_t._info._smbCode]

print
print '_start ',
strStart = ''
for char in obj_data_t._start:
strStart += chr(char)
print strStart
print '_current ',
strCurrent = ''
for char in obj_data_t._current:
strCurrent += chr(char)
print strCurrent,
print
print '_path ',
strPath = ''
for char in obj_data_t._path:
strPath += chr(char)
print strPath,

windll.kernel32.UnmapViewOfFile(addr)
windll.kernel32.CloseHandle(handle)

print
raw_input(' (exit with ENTER) #> OK? ')
#:if
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,998
Latest member
MarissaEub

Latest Threads

Top