Skip to content

Commit 56122cc

Browse files
committed
Extended access to device from Python script
1 parent 74d6f1a commit 56122cc

File tree

5 files changed

+205
-85
lines changed

5 files changed

+205
-85
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ Every device has its own set of scripts: `Init`, `Loop` and `Final`.
115115
Those scripts accessable through device menu or contex menu for device.
116116

117117
`Init` script performs once at program start (when push `Start` button).
118-
It intended for making python `import` instruction, create objects, files etc.
118+
It intended for making python `import` instructions, create objects, files etc.
119119
Modules, objects and files created within will be accessable from `Loop` and `Final` scripts.
120120

121121
`Loop` script performs cyclic until program not stopped.

src/server/python/mbServer.py

Lines changed: 150 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,56 +4,127 @@
44
More details.
55
"""
66

7-
import time
8-
from typing import Union
7+
#from typing import Union
98

109
from PyQt5.QtCore import QSharedMemory
1110

1211
from ctypes import *
1312
import struct
1413

15-
class CControlBlock(Structure):
16-
_fields_ = [("flags" , c_ulong),
17-
("count0x", c_ulong),
18-
("count1x", c_ulong),
19-
("count3x", c_ulong),
20-
("count4x", c_ulong),
21-
("cycle" , c_ulong),
22-
("pycycle", c_ulong)]
14+
MB_DATAORDER_DEFAULT = -1
15+
MB_DATAORDER_LITTLEENDIAN = 0
16+
MB_DATAORDER_BIGENDIAN = 1
17+
18+
MB_REGISTERORDER_DEFAULT = -1
19+
MB_REGISTERORDER_R0R1R2R3 = 0
20+
MB_REGISTERORDER_R3R2R1R0 = 1
21+
MB_REGISTERORDER_R1R0R3R2 = 2
22+
MB_REGISTERORDER_R2R3R0R1 = 3
23+
24+
class CDeviceBlock(Structure):
25+
_fields_ = [("flags" , c_ulong),
26+
("cycle" , c_ulong),
27+
("count0x" , c_ulong),
28+
("count1x" , c_ulong),
29+
("count3x" , c_ulong),
30+
("count4x" , c_ulong),
31+
("exceptionStatusRef", c_ulong),
32+
("byteOrder" , c_long ),
33+
("registerOrder" , c_long ),
34+
("stoDeviceName" , c_ulong),
35+
("stringTableSize" , c_ulong)]
36+
37+
class CPythonBlock(Structure):
38+
_fields_ = [("pycycle" , c_ulong)]
2339

2440
class CMemoryBlockHeader(Structure):
25-
_fields_ = [("changeCounter" , c_ulong),
26-
("changeByteOffset" , c_ulong),
27-
("changeByteCount" , c_ulong),
28-
("dummy" , c_ulong)]
29-
30-
31-
class _MemoryControlBlock:
32-
def __init__(self, memid:str):
33-
shm = QSharedMemory(memid)
41+
_fields_ = [("changeCounter" , c_ulong),
42+
("changeByteOffset" , c_ulong),
43+
("changeByteCount" , c_ulong),
44+
("dummy" , c_ulong)]
45+
46+
47+
class _MbDevice:
48+
def __init__(self, memidprefix:str):
49+
memid_device = memidprefix + ".device"
50+
memid_python = memidprefix + ".python"
51+
memid_mem0x = memidprefix + ".mem0x"
52+
memid_mem1x = memidprefix + ".mem1x"
53+
memid_mem3x = memidprefix + ".mem3x"
54+
memid_mem4x = memidprefix + ".mem4x"
55+
shm = QSharedMemory(memid_device)
3456
res = shm.attach()
3557
if not res:
36-
raise RuntimeError(f"Cannot attach to Shared Memory with id = '{memid}'")
58+
raise RuntimeError(f"Cannot attach to Shared Memory with id = '{memid_device}'")
3759
qptr = shm.data()
3860
size = shm.size()
3961
memptr = c_void_p(qptr.__int__())
40-
pcontrol = cast(memptr, POINTER(CControlBlock))
62+
pcontrol = cast(memptr, POINTER(CDeviceBlock))
4163
self._shm = shm
4264
self._pcontrol = pcontrol
4365
self._control = pcontrol.contents
66+
self._shm.lock()
67+
self._count0x = int(self._control.count0x)
68+
self._count1x = int(self._control.count1x)
69+
self._count3x = int(self._control.count3x)
70+
self._count4x = int(self._control.count4x)
71+
self._excstatusref = int(self._control.exceptionStatusRef)
72+
self._byteorder = int(self._control.byteOrder)
73+
self._registerorder = int(self._control.registerOrder)
74+
self._strtablesize = int(self._control.stringTableSize)
75+
stoDeviceName = int(self._control.stoDeviceName)
76+
self._pmemstrtable = cast(byref(pcontrol[1]),POINTER(c_ubyte*1))
77+
self._name = self._getstring(stoDeviceName)
78+
self._shm.unlock()
79+
# submodules
80+
self._python = _MemoryPythonBlock(memid_python)
81+
self._mem0x = _MemoryBlockBits(memid_mem0x, self._count0x)
82+
self._mem1x = _MemoryBlockBits(memid_mem1x, self._count1x)
83+
self._mem3x = _MemoryBlockRegs(memid_mem3x, self._count3x)
84+
self._mem4x = _MemoryBlockRegs(memid_mem4x, self._count4x)
85+
# Exception status
86+
memtype = self._excstatusref // 10000
87+
self._excoffset = (self._excstatusref % 10000) - 1
88+
if memtype == 0:
89+
self._excmem = self._mem0x
90+
elif memtype == 1:
91+
self._excmem = self._mem1x
92+
elif memtype == 3:
93+
self._excmem = self._mem3x
94+
elif memtype == 4:
95+
self._excmem = self._mem4x
96+
else:
97+
self._excmem = self._mem0x
98+
self._excoffset = 0
4499

45100
def __del__(self):
46101
try:
47102
self._shm.detach()
48103
except RuntimeError:
49104
pass
50105

106+
def _getstring(self, offset:int)->str:
107+
c = 0
108+
while self._pmemstrtable[offset+c][0] != 0:
109+
c += 1
110+
bs = bytes(cast(self._pmemstrtable[offset], POINTER(c_ubyte*c))[0])
111+
return bs.decode('utf-8')
112+
113+
def getname(self)->str:
114+
return self._name
115+
51116
def getflags(self):
52117
self._shm.lock()
53118
r = self._control.flags
54119
self._shm.unlock()
55120
return r
56121

122+
def getcycle(self):
123+
self._shm.lock()
124+
r = self._control.cycle
125+
self._shm.unlock()
126+
return r
127+
57128
def getcount0x(self):
58129
self._shm.lock()
59130
r = self._control.count0x
@@ -78,21 +149,69 @@ def getcount4x(self):
78149
self._shm.unlock()
79150
return r
80151

81-
def getcycle(self):
82-
self._shm.lock()
83-
r = self._control.cycle
84-
self._shm.unlock()
85-
return r
152+
def getexcstatus(self)->int:
153+
return self._excmem.getuint8(self._excoffset)
154+
155+
def setexcstatus(self, value:int)->None:
156+
self._excmem.setuint8(self._excoffset, value)
157+
158+
def getbyteorder(self):
159+
return self._byteorder
160+
161+
def getregisterorder(self):
162+
return self._registerorder
163+
164+
def getpycycle(self):
165+
return self._python.getpycycle()
166+
167+
def _incpycycle(self):
168+
return self._python.incpycycle()
169+
170+
def getmem0x(self):
171+
return self._mem0x
172+
173+
def getmem1x(self):
174+
return self._mem1x
175+
176+
def getmem3x(self):
177+
return self._mem3x
178+
179+
def getmem4x(self):
180+
return self._mem4x
181+
182+
183+
class _MemoryPythonBlock:
184+
def __init__(self, memid:str):
185+
shm = QSharedMemory(memid)
186+
res = shm.attach()
187+
if not res:
188+
raise RuntimeError(f"Cannot attach to Shared Memory with id = '{memid}'")
189+
qptr = shm.data()
190+
self._memsize = shm.size()
191+
memptr = c_void_p(qptr.__int__())
192+
pcontrol = cast(memptr, POINTER(CPythonBlock))
193+
self._shm = shm
194+
self._pcontrol = pcontrol
195+
self._control = pcontrol.contents
196+
self._cyclecounter = 0
197+
198+
def __del__(self):
199+
try:
200+
self._shm.detach()
201+
except RuntimeError:
202+
pass
203+
86204

87205
def getpycycle(self):
88206
self._shm.lock()
89207
r = self._control.pycycle
90208
self._shm.unlock()
91209
return r
92210

93-
def setpycycle(self, value):
211+
def incpycycle(self):
212+
self._cyclecounter += 1
94213
self._shm.lock()
95-
self._control.pycycle = value
214+
self._control.pycycle = self._cyclecounter
96215
self._shm.unlock()
97216

98217

@@ -115,7 +234,7 @@ def __init__(self, memid:str, bytecount:int):
115234
ptrhead = cast(memptr, POINTER(CMemoryBlockHeader))
116235
self._head = ptrhead[0]
117236
self._pmembytes = cast(byref(ptrhead[1]),POINTER(c_ubyte*1))
118-
self._pmaskbytes = cast(byref(cast(byref(ptrhead[1]),POINTER(c_byte*cbytes))[1]),POINTER(c_ubyte*1))
237+
self._pmaskbytes = cast(byref(cast(byref(ptrhead[1]),POINTER(c_byte*cbytes))[1]),POINTER(c_ubyte*1))
119238

120239
def __del__(self):
121240
try:
@@ -172,7 +291,7 @@ def getbytearray(self, byteoffset:int, count:int)->bytearray:
172291
"""
173292
return self._getbytes(byteoffset, count, bytearray)
174293

175-
def setbytes(self, byteoffset:int, value:Union[bytes, bytearray])->None:
294+
def setbytes(self, byteoffset:int, value:type[bytes|bytearray])->None:
176295
"""
177296
@details
178297
Function set `value` (`bytes` or `bytearray`) array object into device memory
@@ -245,7 +364,7 @@ def getbitbytes(self, bitoffset:int, bitcount:int)->bytes:
245364
"""
246365
return bytes(self.getbitbytearray(bitoffset, bitcount))
247366

248-
def setbitbytes(self, bitoffset:int, bitcount:int, value:Union[bytes, bytearray])->None:
367+
def setbitbytes(self, bitoffset:int, bitcount:int, value:type[bytes|bytearray])->None:
249368
"""
250369
@details
251370
Function set `value` (`bytes` or `bytearray`) array object into device memory

src/server/resource/python/programhead.py

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,11 @@
1515

1616
print("PathList from args:"+str(_pathList))
1717

18-
from mbserver import _MemoryControlBlock, _MemoryBlockBits, _MemoryBlockRegs
19-
20-
_sId = _args.memid
21-
22-
_sControl = _sId + ".control"
23-
_sMem0x = _sId + ".mem0x"
24-
_sMem1x = _sId + ".mem1x"
25-
_sMem3x = _sId + ".mem3x"
26-
_sMem4x = _sId + ".mem4x"
27-
28-
print("ControlId: " , _sControl)
29-
print("Memory0xId: ", _sMem0x )
30-
print("Memory1xId: ", _sMem1x )
31-
print("Memory3xId: ", _sMem3x )
32-
print("Memory4xId: ", _sMem4x )
33-
34-
_ctrl = _MemoryControlBlock(_sControl)
35-
mem0x = _MemoryBlockBits(_sMem0x, _ctrl.getcount0x())
36-
mem1x = _MemoryBlockBits(_sMem1x, _ctrl.getcount1x())
37-
mem3x = _MemoryBlockRegs(_sMem3x, _ctrl.getcount3x())
38-
mem4x = _MemoryBlockRegs(_sMem4x, _ctrl.getcount4x())
18+
from mbserver import _MbDevice
19+
20+
mbdevice = _MbDevice(_args.memid)
21+
mem0x = mbdevice.getmem0x()
22+
mem1x = mbdevice.getmem1x()
23+
mem3x = mbdevice.getmem3x()
24+
mem4x = mbdevice.getmem4x()
3925

0 commit comments

Comments
 (0)