Lolitech@545: #!/usr/bin/env python Lolitech@545: # -*- coding: utf-8 -*- Lolitech@545: Lolitech@545: #This file is part of Beremiz, a Integrated Development Environment for Lolitech@545: #programming IEC 61131-3 automates supporting plcopen standard and CanFestival. Lolitech@545: # Lolitech@545: #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD Lolitech@545: # Lolitech@545: #See COPYING file for copyrights details. Lolitech@545: # Lolitech@545: #This library is free software; you can redistribute it and/or Lolitech@545: #modify it under the terms of the GNU General Public Lolitech@545: #License as published by the Free Software Foundation; either Lolitech@545: #version 2.1 of the License, or (at your option) any later version. Lolitech@545: # Lolitech@545: #This library is distributed in the hope that it will be useful, Lolitech@545: #but WITHOUT ANY WARRANTY; without even the implied warranty of Lolitech@545: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lolitech@545: #General Public License for more details. Lolitech@545: # Lolitech@545: #You should have received a copy of the GNU General Public Lolitech@545: #License along with this library; if not, write to the Free Software Lolitech@545: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Lolitech@545: Lolitech@545: import ctypes Lolitech@545: from LPCAppProto import * Lolitech@545: from LPCObject import * Lolitech@545: Lolitech@545: class LPCAppObject(LPCObject): Lolitech@545: def connect(self,comport): Lolitech@545: self.SerialConnection = LPCAppProto(comport,#number Lolitech@545: 115200, #speed Lolitech@545: 2) #timeout Lolitech@545: self.HandleSerialTransaction(IDLETransaction()) Lolitech@545: Lolitech@545: def HandleSerialTransaction(self, transaction): Lolitech@545: if self.SerialConnection is not None: Lolitech@545: try: Lolitech@545: self.PLCStatus, res = self.SerialConnection.HandleTransaction(transaction) Lolitech@545: return res Lolitech@548: except LPCProtoError,e: Lolitech@545: self.pluginsroot.logger.write_error(str(e)+"\n") Lolitech@545: self.SerialConnection = None Lolitech@545: self.PLCStatus = "Disconnected" Lolitech@545: return None Lolitech@545: Lolitech@545: def StartPLC(self, debug=False): Lolitech@545: self.HandleSerialTransaction(STARTTransaction()) Lolitech@545: Lolitech@545: def StopPLC(self): Lolitech@545: self.HandleSerialTransaction(STOPTransaction()) Lolitech@545: Lolitech@548: def ResetPLC(self): Lolitech@545: self.HandleSerialTransaction(RESETTransaction()) Lolitech@545: return self.PLCStatus Lolitech@545: Lolitech@548: def GetPLCstatus(self): Lolitech@545: self.HandleSerialTransaction(IDLETransaction()) Lolitech@545: return self.PLCStatus Lolitech@545: Lolitech@545: def MatchMD5(self, MD5): Lolitech@545: data = self.HandleSerialTransaction(GET_PLCIDTransaction()) Lolitech@545: return data[:32] == MD5 Lolitech@545: Lolitech@545: class IEC_STRING(ctypes.Structure): Lolitech@545: """ Lolitech@545: Must be changed according to changes in iec_types.h Lolitech@545: """ Lolitech@545: _fields_ = [("len", ctypes.c_uint8), Lolitech@545: ("body", ctypes.c_char * 126)] Lolitech@545: Lolitech@545: TypeTranslator = {"BOOL" : (ctypes.c_uint8, lambda x:x.value!=0, lambda t,x:t(x)), Lolitech@545: "STEP" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "TRANSITION" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "ACTION" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "SINT" : (ctypes.c_int8, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "USINT" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "BYTE" : (ctypes.c_uint8, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "STRING" : (IEC_STRING, lambda x:x.body[:x.len], lambda t,x:t(len(x),x)), Lolitech@545: "INT" : (ctypes.c_int16, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "UINT" : (ctypes.c_uint16, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "WORD" : (ctypes.c_uint16, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "WSTRING" : (None, None, None),#TODO Lolitech@545: "DINT" : (ctypes.c_int32, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "UDINT" : (ctypes.c_uint32, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "DWORD" : (ctypes.c_uint32, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "LINT" : (ctypes.c_int64, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "ULINT" : (ctypes.c_uint64, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "LWORD" : (ctypes.c_uint64, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "REAL" : (ctypes.c_float, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: "LREAL" : (ctypes.c_double, lambda x:x.value, lambda t,x:t(x)), Lolitech@545: } Lolitech@545: Lolitech@545: def SetTraceVariablesList(self, idxs): Lolitech@545: """ Lolitech@545: Call ctype imported function to append Lolitech@545: these indexes to registred variables in PLC debugger Lolitech@545: """ Lolitech@545: if idxs: Lolitech@545: buff = "" Lolitech@545: # keep a copy of requested idx Lolitech@545: self._Idxs = idxs[:] Lolitech@545: for idx,iectype,force in idxs: Lolitech@545: idxstr = ctypes.string_at( Lolitech@545: ctypes.pointer( Lolitech@545: ctypes.c_uint32(length)),4) Lolitech@545: if force !=None: Lolitech@545: c_type,unpack_func, pack_func = self.TypeTranslator.get(iectype, (None,None,None)) Lolitech@545: forcedsizestr = chr(ctypes.sizeof(c_type)) Lolitech@545: forcestr = ctypes.string_at( Lolitech@545: ctypes.pointer( Lolitech@545: pack_func(c_type,force)), Lolitech@545: forced_type_size) Lolitech@545: buff += idxstr + forced_type_size_str + forcestr Lolitech@545: else: Lolitech@545: buff += idxstr + chr(0) Lolitech@545: data = self.HandleSerialTransaction( Lolitech@545: SET_TRACE_VARIABLETransaction(buff)) Lolitech@545: else: Lolitech@545: self._Idxs = [] Lolitech@545: Lolitech@545: def GetTraceVariables(self): Lolitech@545: """ Lolitech@545: Return a list of variables, corresponding to the list of required idx Lolitech@545: """ Lolitech@545: offset = 0 Lolitech@545: strbuf = self.HandleSerialTransaction( Lolitech@545: GET_TRACE_VARIABLETransaction()) Lolitech@545: size = len(strbuf) - 4 Lolitech@545: if size > 0 and self.PLCStatus == "Started": Lolitech@545: tick = ctypes.cast( Lolitech@545: ctypes.c_char_p(strbuf[:4]), Lolitech@545: ctypes.POINTER(ctypes.c_int)).contents Lolitech@545: buffer = ctypes.cast( Lolitech@545: ctypes.c_char_p(strbuf[4:]), Lolitech@545: ctypes.c_void_p) Lolitech@545: for idx, iectype, forced in self._Idxs: Lolitech@545: cursor = ctypes.c_void_p(buffer.value + offset) Lolitech@545: c_type,unpack_func, pack_func = self.TypeTranslator.get(iectype, (None,None,None)) Lolitech@545: if c_type is not None and offset < size: Lolitech@545: res.append(unpack_func(ctypes.cast(cursor, Lolitech@545: ctypes.POINTER(c_type)).contents)) Lolitech@545: offset += ctypes.sizeof(c_type) Lolitech@545: else: Lolitech@557: #if c_type is None: Lolitech@557: #PLCprint("Debug error - " + iectype + " not supported !") Lolitech@557: #if offset >= size: Lolitech@557: #PLCprint("Debug error - buffer too small !") Lolitech@545: break Lolitech@545: if offset and offset == size: Lolitech@545: return self.PLCStatus, tick.value, res Lolitech@557: #PLCprint("Debug error - wrong buffer unpack !") Lolitech@545: return self.PLCStatus, None, None Lolitech@545: