author | Edouard TISSERANT <edouard.tisserant@gmail.com> |
Wed, 23 Dec 2009 22:23:02 +0100 | |
changeset 532 | a822b0b64252 |
parent 525 | e43bc748d1fe |
child 545 | 627e5c636a4f |
permissions | -rwxr-xr-x |
448 | 1 |
#!/usr/bin/env python |
2 |
# -*- coding: utf-8 -*- |
|
3 |
||
4 |
#This file is part of Beremiz, a Integrated Development Environment for |
|
5 |
#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. |
|
6 |
# |
|
7 |
#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
|
8 |
# |
|
9 |
#See COPYING file for copyrights details. |
|
10 |
# |
|
11 |
#This library is free software; you can redistribute it and/or |
|
12 |
#modify it under the terms of the GNU General Public |
|
13 |
#License as published by the Free Software Foundation; either |
|
14 |
#version 2.1 of the License, or (at your option) any later version. |
|
15 |
# |
|
16 |
#This library is distributed in the hope that it will be useful, |
|
17 |
#but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18 |
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
19 |
#General Public License for more details. |
|
20 |
# |
|
21 |
#You should have received a copy of the GNU General Public |
|
22 |
#License along with this library; if not, write to the Free Software |
|
23 |
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
24 |
||
25 |
import ctypes, os, commands, types, sys |
|
453 | 26 |
from LPCProto import * |
448 | 27 |
|
28 |
class LPCObject(): |
|
508 | 29 |
def __init__(self,pluginsroot, location): |
30 |
self.PLCStatus = "Disconnected" |
|
448 | 31 |
self.pluginsroot = pluginsroot |
32 |
self.PLCprint = pluginsroot.logger.write |
|
453 | 33 |
self._Idxs = [] |
508 | 34 |
self.UpdateLocation(location) |
35 |
||
36 |
def UpdateLocation(self, location): |
|
37 |
# Is that a comport ? |
|
38 |
if len(location) == 5 and\ |
|
39 |
location.startswith("COM") and \ |
|
40 |
location[3].isdigit() and \ |
|
41 |
location[4]==":" : |
|
42 |
self.StorageConnection = None |
|
453 | 43 |
try: |
508 | 44 |
comport = int(location[3]) - 1 |
45 |
self.SerialConnection = LPCProto(comport,#number |
|
46 |
115200, #speed |
|
47 |
2) #timeout |
|
48 |
# This will update status |
|
49 |
self.HandleSerialTransaction(IDLETransaction()) |
|
453 | 50 |
except Exception,e: |
51 |
self.pluginsroot.logger.write_error(str(e)+"\n") |
|
52 |
self.SerialConnection = None |
|
508 | 53 |
self.PLCStatus = "Disconnected" |
54 |
# or a drive unit ? |
|
55 |
elif len(location)==2 and \ |
|
56 |
location[0].isalpha() and \ |
|
57 |
location[1] == ':' : |
|
453 | 58 |
self.SerialConnection = None |
520 | 59 |
if os.path.exists(location): |
508 | 60 |
self.StorageConnection = location |
61 |
self.PLCStatus = "Stopped" |
|
62 |
else: |
|
63 |
self.pluginsroot.logger.write_error("Drive "+ |
|
64 |
location+ |
|
65 |
" do not exist !\n") |
|
66 |
self.StorageConnection = None |
|
67 |
self.PLCStatus = "Disconnected" |
|
68 |
||
69 |
def HandleSerialTransaction(self, transaction): |
|
70 |
if self.SerialConnection is not None: |
|
71 |
try: |
|
72 |
self.PLCStatus, res = self.SerialConnection.HandleTransaction(transaction) |
|
73 |
return res |
|
74 |
except LPCError,e: |
|
75 |
self.pluginsroot.logger.write_error(str(e)+"\n") |
|
76 |
self.SerialConnection = None |
|
77 |
self.PLCStatus = "Disconnected" |
|
78 |
return None |
|
453 | 79 |
|
448 | 80 |
def StartPLC(self, debug=False): |
81 |
PLCprint("StartPLC") |
|
453 | 82 |
self.HandleSerialTransaction(STARTTransaction()) |
448 | 83 |
|
84 |
def StopPLC(self): |
|
85 |
PLCprint("StopPLC") |
|
453 | 86 |
self.HandleSerialTransaction(STOPTransaction()) |
448 | 87 |
|
88 |
def ForceReload(self): |
|
453 | 89 |
pass |
448 | 90 |
|
91 |
def GetPLCstatus(self): |
|
508 | 92 |
self.HandleSerialTransaction(IDLETransaction()) |
93 |
return self.PLCStatus |
|
448 | 94 |
|
95 |
def NewPLC(self, md5sum, data, extrafiles): |
|
521
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
96 |
if os.path.exists(self.StorageConnection): |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
97 |
firmwarepath = os.path.join( |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
98 |
self.StorageConnection, |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
99 |
"firmware.bin") |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
100 |
try: |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
101 |
if os.path.exists(firmwarepath ): |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
102 |
os.unlink(firmwarepath) |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
103 |
f = open(firmwarepath, "wb") |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
104 |
f.write(data) |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
105 |
f.close() |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
106 |
return True |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
107 |
except LPCError,e: |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
108 |
self.StorageConnection = None |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
109 |
self.PLCStatus = "Disconnected" |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
110 |
self.pluginsroot.logger.write_error( |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
111 |
"LPC transfer error : "+ |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
112 |
str(e)+"\n") |
448 | 113 |
|
114 |
def MatchMD5(self, MD5): |
|
521
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
115 |
data = self.HandleSerialTransaction(GET_PLCIDTransaction()) |
525
e43bc748d1fe
LPCobject writes PLC info string to stdout, for LPC composer to update
Edouard TISSERANT <edouard.tisserant@gmail.com>
parents:
521
diff
changeset
|
116 |
print "PLCINFO",data[32:] |
521
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
117 |
return data[:32] == MD5 |
02cb9e5fb6f6
LPC transfer tested, added PLCInfo along MD5 checksum while invoking makefile
edouard
parents:
520
diff
changeset
|
118 |
|
448 | 119 |
class IEC_STRING(ctypes.Structure): |
120 |
""" |
|
121 |
Must be changed according to changes in iec_types.h |
|
122 |
""" |
|
123 |
_fields_ = [("len", ctypes.c_uint8), |
|
502 | 124 |
("body", ctypes.c_char * 126)] |
448 | 125 |
|
502 | 126 |
TypeTranslator = {"BOOL" : (ctypes.c_uint8, lambda x:x.value!=0, lambda t,x:t(x)), |
127 |
"STEP" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), |
|
128 |
"TRANSITION" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), |
|
129 |
"ACTION" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), |
|
130 |
"SINT" : (ctypes.c_int8, lambda x:x.value, lambda t,x:t(x)), |
|
131 |
"USINT" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), |
|
132 |
"BYTE" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), |
|
133 |
"STRING" : (IEC_STRING, lambda x:x.body[:x.len], lambda t,x:t(len(x),x)), |
|
134 |
"INT" : (ctypes.c_int16, lambda x:x.value, lambda t,x:t(x)), |
|
135 |
"UINT" : (ctypes.c_uint16, lambda x:x.value, lambda t,x:t(x)), |
|
136 |
"WORD" : (ctypes.c_uint16, lambda x:x.value, lambda t,x:t(x)), |
|
137 |
"WSTRING" : (None, None, None),#TODO |
|
138 |
"DINT" : (ctypes.c_int32, lambda x:x.value, lambda t,x:t(x)), |
|
139 |
"UDINT" : (ctypes.c_uint32, lambda x:x.value, lambda t,x:t(x)), |
|
140 |
"DWORD" : (ctypes.c_uint32, lambda x:x.value, lambda t,x:t(x)), |
|
141 |
"LINT" : (ctypes.c_int64, lambda x:x.value, lambda t,x:t(x)), |
|
142 |
"ULINT" : (ctypes.c_uint64, lambda x:x.value, lambda t,x:t(x)), |
|
143 |
"LWORD" : (ctypes.c_uint64, lambda x:x.value, lambda t,x:t(x)), |
|
144 |
"REAL" : (ctypes.c_float, lambda x:x.value, lambda t,x:t(x)), |
|
145 |
"LREAL" : (ctypes.c_double, lambda x:x.value, lambda t,x:t(x)), |
|
448 | 146 |
} |
502 | 147 |
|
148 |
def SetTraceVariablesList(self, idxs): |
|
149 |
""" |
|
150 |
Call ctype imported function to append |
|
151 |
these indexes to registred variables in PLC debugger |
|
152 |
""" |
|
153 |
if idxs: |
|
154 |
buff = "" |
|
155 |
# keep a copy of requested idx |
|
156 |
self._Idxs = idxs[:] |
|
157 |
for idx,iectype,force in idxs: |
|
158 |
idxstr = ctypes.string_at( |
|
159 |
ctypes.pointer( |
|
160 |
ctypes.c_uint32(length)),4) |
|
161 |
if force !=None: |
|
162 |
c_type,unpack_func, pack_func = self.TypeTranslator.get(iectype, (None,None,None)) |
|
163 |
forcedsizestr = chr(ctypes.sizeof(c_type)) |
|
164 |
forcestr = ctypes.string_at( |
|
165 |
ctypes.pointer( |
|
166 |
pack_func(c_type,force)), |
|
167 |
forced_type_size) |
|
168 |
buff += idxstr + forced_type_size_str + forcestr |
|
169 |
else: |
|
170 |
buff += idxstr + chr(0) |
|
508 | 171 |
data = self.HandleSerialTransaction( |
502 | 172 |
SET_TRACE_VARIABLETransaction(buff)) |
173 |
else: |
|
174 |
self._Idxs = [] |
|
175 |
||
448 | 176 |
def GetTraceVariables(self): |
177 |
""" |
|
178 |
Return a list of variables, corresponding to the list of required idx |
|
179 |
""" |
|
508 | 180 |
offset = 0 |
181 |
strbuf = self.HandleSerialTransaction( |
|
182 |
GET_TRACE_VARIABLETransaction()) |
|
183 |
size = len(strbuf) - 4 |
|
184 |
if size > 0 and self.PLCStatus == "Started": |
|
185 |
tick = ctypes.cast( |
|
186 |
ctypes.c_char_p(strbuf[:4]), |
|
187 |
ctypes.POINTER(ctypes.c_int)).contents |
|
188 |
buffer = ctypes.cast( |
|
189 |
ctypes.c_char_p(strbuf[4:]), |
|
190 |
ctypes.c_void_p) |
|
191 |
for idx, iectype, forced in self._Idxs: |
|
192 |
cursor = ctypes.c_void_p(buffer.value + offset) |
|
193 |
c_type,unpack_func, pack_func = self.TypeTranslator.get(iectype, (None,None,None)) |
|
194 |
if c_type is not None and offset < size: |
|
195 |
res.append(unpack_func(ctypes.cast(cursor, |
|
196 |
ctypes.POINTER(c_type)).contents)) |
|
197 |
offset += ctypes.sizeof(c_type) |
|
198 |
else: |
|
199 |
if c_type is None: |
|
200 |
PLCprint("Debug error - " + iectype + " not supported !") |
|
201 |
if offset >= size: |
|
202 |
PLCprint("Debug error - buffer too small !") |
|
203 |
break |
|
204 |
if offset and offset == size: |
|
502 | 205 |
return self.PLCStatus, tick.value, res |
508 | 206 |
PLCprint("Debug error - wrong buffer unpack !") |
453 | 207 |
return self.PLCStatus, None, None |
448 | 208 |