Skip to content

Commit 3a453d2

Browse files
committed
Added webinterface
1 parent 22a10de commit 3a453d2

File tree

9 files changed

+364
-136
lines changed

9 files changed

+364
-136
lines changed

dcp.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010
"ip": PNDCPBlock.IP_ADDRESS
1111
}
1212

13+
14+
class DCPDeviceDescription:
15+
def __init__(self, mac, blocks):
16+
self.mac = mac2s(mac)
17+
self.name = blocks[PNDCPBlock.NAME_OF_STATION].decode()
18+
self.ip = s2ip(blocks[PNDCPBlock.IP_ADDRESS][0:4])
19+
self.netmask = s2ip(blocks[PNDCPBlock.IP_ADDRESS][4:8])
20+
self.gateway = s2ip(blocks[PNDCPBlock.IP_ADDRESS][8:12])
21+
self.vendorHigh, self.vendorLow, self.devHigh, self.devLow = unpack(">BBBB", blocks[PNDCPBlock.DEVICE_ID][0:4])
22+
23+
1324
def get_param(s, src, target, param):
1425
dst = s2mac(target)
1526

@@ -59,13 +70,19 @@ def send_request(s, src, t, value):
5970
s.send(bytes(eth))
6071

6172

62-
def read_response(s, my_mac, want=None, debug=False):
63-
ret = []
73+
def read_response(s, my_mac, to=20, once=False, debug=False):
74+
ret = {}
6475
found = []
76+
s.settimeout(2)
6577
try:
66-
with timeout(20):
67-
while s is not None:
68-
data = s.recv(1522)
78+
with max_timeout(to) as t:
79+
while True:
80+
if t.timed_out:
81+
break
82+
try:
83+
data = s.recv(1522)
84+
except timeout:
85+
continue
6986

7087
# nur Ethernet Pakete an uns und vom Ethertype Profinet
7188
eth = EthernetHeader(data)
@@ -81,19 +98,22 @@ def read_response(s, my_mac, want=None, debug=False):
8198
# Blöcke der Response parsen
8299
blocks = pro.payload
83100
length = pro.length
101+
parsed = {}
84102

85103
while length > 6:
86104
block = PNDCPBlock(blocks)
87-
if want is None or (block.option, block.suboption) in want:
88-
found.append((block.option, block.suboption))
89-
ret.append(block)
105+
blockoption = (block.option, block.suboption)
106+
parsed[blockoption] = block.payload
90107

91108
block_len = block.length
92-
if debug:
93-
if (block.option, block.suboption) == PNDCPBlock.NAME_OF_STATION:
94-
print("Name of Station: %s" % block.payload)
95-
elif (block.option, block.suboption) == PNDCPBlock.IP_ADDRESS:
96-
print(str(block.parse_ip()))
109+
if blockoption == PNDCPBlock.NAME_OF_STATION:
110+
debug and print("Name of Station: %s" % block.payload)
111+
parsed["name"] = block.payload
112+
elif blockoption == PNDCPBlock.IP_ADDRESS:
113+
debug and print(str(block.parse_ip()))
114+
parsed["ip"] = s2ip(block.payload[0:4])
115+
elif blockoption == PNDCPBlock.DEVICE_ID:
116+
parsed["devId"] = block.payload
97117

98118
# Padding:
99119
if block_len % 2 == 1:
@@ -102,8 +122,10 @@ def read_response(s, my_mac, want=None, debug=False):
102122
# geparsten Block entfernen
103123
blocks = blocks[block_len+4:]
104124
length -= 4 + block_len
125+
126+
ret[eth.src] = parsed
105127

106-
if want is not None and sorted(found) == sorted(want):
128+
if once:
107129
break
108130

109131
except TimeoutError:

main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
elif args.action.startswith("read") or args.action.startswith("write"):
3535
print("Getting station info ...")
3636
info = rpc.get_station_info(s, src, args.target)
37-
con = rpc.RPCCon(*info)
37+
con = rpc.RPCCon(info)
3838

3939
print("Connecting to device ...")
4040
con.connect(src)

rpc.py

Lines changed: 81 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from struct import unpack
22
from socket import MSG_WAITALL
3+
from datetime import datetime
34

45
from util import *
56
from protocol import *
@@ -9,118 +10,110 @@
910

1011
def get_station_info(s, src, name):
1112
dcp.send_request(s, src, PNDCPBlock.NAME_OF_STATION, bytes(name, 'utf-8'))
12-
ret = dcp.read_response(s, src, want=(PNDCPBlock.IP_ADDRESS, PNDCPBlock.DEVICE_ID))
13-
14-
ip = ""
15-
vendorHigh = vendorLow = devHigh = devLow = 0
16-
for block in ret:
17-
if (block.option, block.suboption) == PNDCPBlock.IP_ADDRESS:
18-
ip = s2ip(block.payload[0:4])
19-
if (block.option, block.suboption) == PNDCPBlock.DEVICE_ID:
20-
vendorHigh, vendorLow, devHigh, devLow = unpack(">BBBB", block.payload[0:4])
21-
22-
return ip, vendorHigh, vendorLow, devHigh, devLow
13+
resp = list(dcp.read_response(s, src, once=True).items())[0]
14+
return dcp.DCPDeviceDescription(*resp)
2315

2416

2517
class RPCCon:
26-
def __init__(self, ip, vendorHigh, vendorLow, devHigh, devLow):
27-
self.peer = (ip, 0x8894)
28-
self.ip = ip
18+
def __init__(self, info):
19+
self.info = info
20+
self.peer = (info.ip, 0x8894)
21+
22+
self.ar_uuid = bytes([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
23+
self.activity_uuid = ar_uuid
24+
25+
self.local_object_uuid = PNRPCHeader.OBJECT_UUID_PREFIX + bytes([0x00, 0x01, 0x76, 0x54, 0x32, 0x10])
26+
self.remote_object_uuid = PNRPCHeader.OBJECT_UUID_PREFIX + bytes([0x00, 0x01, self.info.devHigh, self.info.devLow, self.info.vendorHigh, self.info.vendorLow])
27+
28+
self.live = None
29+
2930
self.u = socket(AF_INET, SOCK_DGRAM)
30-
self.vendorHigh, self.vendorLow, self.devHigh, self.devLow = vendorHigh, vendorLow, devHigh, devLow
3131

32-
def read(self, api, slot, subslot, idx):
33-
block = PNBlockHeader(PNBlockHeader.IDOReadRequestHeader, 60, 0x01, 0x00)
34-
iod = PNIODHeader(bytes(block), 0,
35-
bytes([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]),
36-
api, slot, subslot, 0, idx, 4096, bytes(16), bytes(8), payload=bytes())
37-
nrd = PNNRDData(1500, len(iod), 1500, 0, len(iod), payload=iod)
38-
rpc = PNRPCHeader(0x04, PNRPCHeader.REQUEST,
32+
33+
def _create_rpc(self, operation, nrd):
34+
return PNRPCHeader(0x04, PNRPCHeader.REQUEST,
3935
0x20, # Flags1
4036
0x00, # Flags2
4137
bytes([0x00, 0x00, 0x00]), # DRep
4238
0x00, # Serial High
43-
PNRPCHeader.OBJECT_UUID_PREFIX + bytes([0x00, 0x01, self.devHigh, self.devLow, self.vendorHigh, self.vendorLow]), # ObjectUUID
39+
self.remote_object_uuid,
4440
PNRPCHeader.IFACE_UUID_DEVICE,
45-
bytes([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]), # ActivityUUID
41+
self.activity_uuid,
4642
0, # ServerBootTime
4743
1, # InterfaceVersion
4844
0, # SequenceNumber
49-
PNRPCHeader.READ, # OperationNumber
45+
operation,
5046
0xFFFF, # InterfaceHint
5147
0xFFFF, # ActivityHint
52-
len(nrd), # LengthOfBody
48+
len(nrd),
5349
0, # FragmentNumber
5450
0, # AuthenticationProtocol
5551
0, # SerialLow
5652
payload=nrd
5753
)
54+
55+
def _create_nrd(self, payload):
56+
return PNNRDData(1500, len(payload), 1500, 0, len(payload), payload=payload)
57+
58+
def _check_timeout(self):
59+
if (datetime.now() - self.live).seconds >= 10:
60+
self.connect()
61+
62+
63+
def connect(self, src_mac=None):
64+
if self.live is None:
65+
self.src_mac = src_mac
66+
67+
block = PNBlockHeader(0x0101, PNARBlockRequest.fmt_size - 2, 0x01, 0x00)
68+
ar = PNARBlockRequest(bytes(block),
69+
0x0006, # AR Type
70+
self.ar_uuid, # AR UUID
71+
0x1234, # Session key
72+
src_mac,
73+
self.local_object_uuid,
74+
0x131, # AR Properties
75+
100, # Timeout factor
76+
0x8892, # udp port?
77+
2,
78+
bytes("tp", encoding="utf-8"), payload=bytes()
79+
)
80+
nrd = self._create_nrd(ar)
81+
rpc = self._create_rpc(PNRPCHeader.CONNECT, nrd)
5882
self.u.sendto(bytes(rpc), self.peer)
5983

6084
data = self.u.recvfrom(4096)[0]
61-
rpc = PNRPCHeader(data)
62-
nrd = PNNRDData(rpc.payload)
63-
iod = PNIODHeader(nrd.payload)
64-
block = PNBlockHeader(iod.block_header)
85+
# ignore response
86+
#rpc = PNRPCHeader(data)
87+
#nrd = PNNRDData(rpc.payload)
88+
#ar = PNARBlockRequest(nrd.payload)
89+
#block = PNBlockHeader(iod.block_header)
6590

66-
return iod
91+
self.live = datetime.now()
6792

68-
def write(self, api, slot, subslot, idx, data):
69-
block = PNBlockHeader(0x8, 60, 0x01, 0x00)
70-
iod = PNIODHeader(bytes(block), 0,
71-
bytes([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]),
72-
api, slot, subslot, 0, idx, len(data), bytes(16), bytes(8), payload=bytes(data))
73-
nrd = PNNRDData(1500, len(iod), 1500, 0, len(iod), payload=iod)
74-
rpc = PNRPCHeader(0x04, PNRPCHeader.REQUEST,
75-
0x20, # Flags1
76-
0x00, # Flags2
77-
bytes([0x00, 0x00, 0x00]), # DRep
78-
0x00, # Serial High
79-
PNRPCHeader.OBJECT_UUID_PREFIX + bytes([0x00, 0x01, self.devHigh, self.devLow, self.vendorHigh, self.vendorLow]), # ObjectUUID
80-
PNRPCHeader.IFACE_UUID_DEVICE,
81-
bytes([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]), # ActivityUUID
82-
0, # ServerBootTime
83-
1, # InterfaceVersion
84-
0, # SequenceNumber
85-
PNRPCHeader.WRITE, # OperationNumber
86-
0xFFFF, # InterfaceHint
87-
0xFFFF, # ActivityHint
88-
len(nrd), # LengthOfBody
89-
0, # FragmentNumber
90-
0, # AuthenticationProtocol
91-
0, # SerialLow
92-
payload=nrd
93-
)
93+
def read(self, api, slot, subslot, idx):
94+
self._check_timeout()
95+
96+
block = PNBlockHeader(PNBlockHeader.IDOReadRequestHeader, 60, 0x01, 0x00)
97+
iod = PNIODHeader(bytes(block), 0, self.ar_uuid, api, slot, subslot, 0, idx, 4096, bytes(16), bytes(8), payload=bytes())
98+
nrd = self._create_nrd(iod)
99+
rpc = self._create_rpc(PNRPCHeader.READ, nrd)
94100
self.u.sendto(bytes(rpc), self.peer)
95101

96102
data = self.u.recvfrom(4096)[0]
103+
rpc = PNRPCHeader(data)
104+
nrd = PNNRDData(rpc.payload)
105+
iod = PNIODHeader(nrd.payload)
106+
block = PNBlockHeader(iod.block_header)
107+
108+
self.live = datetime.now()
97109

98110
return iod
99111

100112
def read_implicit(self, api, slot, subslot, idx):
101113
block = PNBlockHeader(PNBlockHeader.IDOReadRequestHeader, 60, 0x01, 0x00)
102114
iod = PNIODHeader(bytes(block), 0, bytes(16), api, slot, subslot, 0, idx, 4096, bytes(16), bytes(8), payload=bytes())
103-
nrd = PNNRDData(1500, len(iod), 1500, 0, len(iod), payload=iod)
104-
rpc = PNRPCHeader(0x04, PNRPCHeader.REQUEST,
105-
0x20, # Flags1
106-
0x00, # Flags2
107-
bytes([0x00, 0x00, 0x00]), # DRep
108-
0x00, # Serial High
109-
PNRPCHeader.OBJECT_UUID_PREFIX + bytes([0x00, 0x01, self.devHigh, self.devLow, self.vendorHigh, self.vendorLow]), # ObjectUUID
110-
PNRPCHeader.IFACE_UUID_DEVICE,
111-
bytes([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]), # ActivityUUID
112-
0, # ServerBootTime
113-
1, # InterfaceVersion
114-
0, # SequenceNumber
115-
PNRPCHeader.IMPLICIT_READ, # OperationNumber
116-
0xFFFF, # InterfaceHint
117-
0xFFFF, # ActivityHint
118-
len(nrd), # LengthOfBody
119-
0, # FragmentNumber
120-
0, # AuthenticationProtocol
121-
0, # SerialLow
122-
payload=nrd
123-
)
115+
nrd = self._create_nrd(iod)
116+
rpc = self._create_rpc(PNRPCHeader.IMPLICIT_READ, nrd)
124117
self.u.sendto(bytes(rpc), self.peer)
125118

126119
data = self.u.recvfrom(4096)[0]
@@ -131,51 +124,20 @@ def read_implicit(self, api, slot, subslot, idx):
131124

132125
return iod
133126

134-
def connect(self, src_mac):
135-
block = PNBlockHeader(0x0101, PNARBlockRequest.fmt_size - 2, 0x01, 0x00)
136-
ar = PNARBlockRequest(bytes(block),
137-
0x0006, # AR Type
138-
bytes([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]), # AR UUID
139-
0x1234, # Session key
140-
src_mac,
141-
PNRPCHeader.OBJECT_UUID_PREFIX + bytes([0x00, 0x01, 0x76, 0x54, 0x32, 0x10]),
142-
0x131, # AR Properties
143-
100, # Timeout factor
144-
0x8892, # udp port?
145-
2,
146-
bytes("tp", encoding="utf-8"), payload=bytes()
147-
)
148-
nrd = PNNRDData(1500, len(ar), 1500, 0, len(ar), payload=ar)
149-
rpc = PNRPCHeader(0x04, PNRPCHeader.REQUEST,
150-
0x20, # Flags1
151-
0x00, # Flags2
152-
bytes([0x00, 0x00, 0x00]), # DRep
153-
0x00, # Serial High
154-
PNRPCHeader.OBJECT_UUID_PREFIX + bytes([0x00, 0x01, self.devHigh, self.devLow, self.vendorHigh, self.vendorLow]), # ObjectUUID
155-
PNRPCHeader.IFACE_UUID_DEVICE,
156-
bytes([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]), # ActivityUUID
157-
0, # ServerBootTime
158-
1, # InterfaceVersion
159-
0, # SequenceNumber
160-
PNRPCHeader.CONNECT, # OperationNumber
161-
0xFFFF, # InterfaceHint
162-
0xFFFF, # ActivityHint
163-
len(nrd), # LengthOfBody
164-
0, # FragmentNumber
165-
0, # AuthenticationProtocol
166-
0, # SerialLow
167-
payload=nrd
168-
)
127+
def write(self, api, slot, subslot, idx, data):
128+
self._check_timeout()
129+
block = PNBlockHeader(0x8, 60, 0x01, 0x00)
130+
iod = PNIODHeader(bytes(block), 0, self.ar_uuid, api, slot, subslot, 0, idx, len(data), bytes(16), bytes(8), payload=bytes(data))
131+
nrd = self._create_nrd(iod)
132+
rpc = self._create_rpc(PNRPCHeader.WRITE, nrd)
169133
self.u.sendto(bytes(rpc), self.peer)
170134

171135
data = self.u.recvfrom(4096)[0]
172-
#rpc = PNRPCHeader(data)
173-
#nrd = PNNRDData(rpc.payload)
174-
#ar = PNARBlockRequest(nrd.payload)
175-
#block = PNBlockHeader(iod.block_header)
136+
# ignore response
176137

177-
return ar
178-
138+
self.live = datetime.now()
139+
140+
179141
def read_inm0filter(self):
180142
data = self.read(api=0, slot=0, subslot=0, idx=0xF840).payload
181143
block = PNBlockHeader(data)

0 commit comments

Comments
 (0)