LPC connector enhancements
authoredouard
Fri, 04 Dec 2009 15:16:37 +0100
changeset 453 923d036dfa90
parent 452 2d0718a05cc7
child 454 fd316d2babd5
LPC connector enhancements
connectors/LPC/LPCObject.py
connectors/LPC/LPCProto.py
--- a/connectors/LPC/LPCObject.py	Fri Dec 04 15:15:57 2009 +0100
+++ b/connectors/LPC/LPCObject.py	Fri Dec 04 15:16:37 2009 +0100
@@ -25,96 +25,59 @@
 from threading import Timer, Thread, Lock
 import ctypes, os, commands, types, sys
 import traceback
+from LPCProto import *
 
 class LPCObject():
-    _Idxs = []
     def __init__(self,pluginsroot):
         self.PLCStatus = "Stopped"
         self.pluginsroot = pluginsroot
         self.PLCprint = pluginsroot.logger.write
-    
+        self.SerialConnection = None
+        self._Idxs = []
+        
+    def HandleSerialTransaction(self, transaction):
+        if self.SerialConnection is None:
+            try:
+                self.SerialConnection = LPCProto(6,115200,2)
+            except Exception,e:
+                self.pluginsroot.logger.write_error(str(e)+"\n")
+                self.SerialConnection = None
+                return "Disconnected", res
+        try:
+            return self.SerialConnection.HandleTransaction(transaction)
+        except LPCError,e:
+            #pluginsroot.logger.write_error(traceback.format_exc())
+            self.pluginsroot.logger.write_error(str(e)+"\n")
+            self.SerialConnection = None
+            return "Disconnected", res
+
     def StartPLC(self, debug=False):
         PLCprint("StartPLC")
-        if self.CurrentPLCFilename is not None:
-            self.PLCStatus = "Started"
-            self.PythonThread = Thread(target=self.PythonThreadProc, args=[debug])
-            self.PythonThread.start()
+        self.HandleSerialTransaction(STARTTransaction())
             
     def StopPLC(self):
         PLCprint("StopPLC")
-        if self.PLCStatus == "Started":
-            self._stopPLC()
-            return True
-        return False
+        self.HandleSerialTransaction(STOPTransaction())
 
     def ForceReload(self):
-        # respawn python interpreter
-        Timer(0.1,self._Reload).start()
-        return True
+        pass
 
     def GetPLCstatus(self):
-        return self.PLCStatus
+        status,data = self.HandleSerialTransaction(IDLETransaction())
+        return status
     
     def NewPLC(self, md5sum, data, extrafiles):
-        PLCprint("NewPLC (%s)"%md5sum)
-        if self.PLCStatus in ["Stopped", "Empty", "Broken"]:
-            NewFileName = md5sum + lib_ext
-            extra_files_log = os.path.join(self.workingdir,"extra_files.txt")
-            try:
-                os.remove(os.path.join(self.workingdir,
-                                       self.CurrentPLCFilename))
-                for filename in file(extra_files_log, "r").readlines() + [extra_files_log]:
-                    try:
-                        os.remove(os.path.join(self.workingdir, filename.strip()))
-                    except:
-                        pass
-            except:
-                pass
-                        
-            try:
-                # Create new PLC file
-                open(os.path.join(self.workingdir,NewFileName),
-                     'wb').write(data)
-        
-                # Store new PLC filename based on md5 key
-                open(self._GetMD5FileName(), "w").write(md5sum)
-        
-                # Then write the files
-                log = file(extra_files_log, "w")
-                for fname,fdata in extrafiles:
-                    fpath = os.path.join(self.workingdir,fname)
-                    open(fpath, "wb").write(fdata)
-                    log.write(fname+'\n')
-
-                # Store new PLC filename
-                self.CurrentPLCFilename = NewFileName
-            except:
-                PLCprint(traceback.format_exc())
-                return False
-            if self.PLCStatus == "Empty":
-                self.PLCStatus = "Stopped"
-            return True
-        return False
+        pass
 
     def MatchMD5(self, MD5):
-        try:
-            last_md5 = open(self._GetMD5FileName(), "r").read()
-            return last_md5 == MD5
-        except:
-            return False
+        status,data = self.HandleSerialTransaction(PLCIDTransaction())
+        return data == MD5
     
     def SetTraceVariablesList(self, idxs):
-        """
-        Call ctype imported function to append 
-        these indexes to registred variables in PLC debugger
-        """
-        self._suspendDebug()
-        # keep a copy of requested idx
-        self._Idxs = idxs[:]
-        self._ResetDebugVariables()
-        for idx in idxs:
-            self._RegisterDebugVariable(idx)
-        self._resumeDebug()
+        self._Idxs = idxs[]
+        status,data = self.HandleSerialTransaction(
+               SET_TRACE_VARIABLETransaction(
+                     ''.join(map(chr,idx))))
 
     class IEC_STRING(ctypes.Structure):
         """
@@ -149,29 +112,25 @@
         """
         Return a list of variables, corresponding to the list of required idx
         """
-        if self.PLCStatus == "Started":
-            self.PLClibraryLock.acquire()
-            tick = self._WaitDebugData()
-            #PLCprint("Debug tick : %d"%tick)
-            if tick == 2**32 - 1:
-                tick = -1
-                res = None
-            else:
-                idx = ctypes.c_int()
-                typename = ctypes.c_char_p()
-                res = []
-        
-                for given_idx in self._Idxs:
-                    buffer=self._IterDebugData(ctypes.byref(idx), ctypes.byref(typename))
-                    c_type,unpack_func = self.TypeTranslator.get(typename.value, (None,None))
-                    if c_type is not None and given_idx == idx.value:
-                        res.append(unpack_func(ctypes.cast(buffer,
-                                                           ctypes.POINTER(c_type)).contents))
-                    else:
-                        PLCprint("Debug error idx : %d, expected_idx %d, type : %s"%(idx.value, given_idx,typename.value))
-                        res.append(None)
-            self._FreeDebugData()
-            self.PLClibraryLock.release()
-            return tick, res
-        return -1, None
+        status,data = self.HandleSerialTransaction(GET_TRACE_VARIABLETransaction())
+        if data is not None:
+            # transform serial string to real byte string in memory 
+            buffer = ctypes.c_char_p(data)
+            # tick is first value in buffer
+            tick = ctypes.cast(buffer,ctypes.POINTER(ctypes.c_uint32)).contents
+            # variable data starts just after tick 
+            cursorp = ctypes.addressof(buffer) = ctypes.sizeof(ctypes.c_uint32)
+            endp = offset + len(data)
+            for idx, iectype in self._Idxs:
+                cursor = ctypes.c_void_p(cursorp)
+                c_type,unpack_func = self.TypeTranslator.get(iectype, (None,None))
+                if c_type is not None and cursorp < endp:
+                    res.append(unpack_func(ctypes.cast(cursor,
+                                                       ctypes.POINTER(c_type)).contents))
+                    cursorp += ctypes.sizeof(c_type) 
+                else:
+                    PLCprint("Debug error !")
+                        break
+            return self.PLCStatus, tick, res
+        return self.PLCStatus, None, None
 
--- a/connectors/LPC/LPCProto.py	Fri Dec 04 15:15:57 2009 +0100
+++ b/connectors/LPC/LPCProto.py	Fri Dec 04 15:16:37 2009 +0100
@@ -1,16 +1,9 @@
 import serial
+import exceptions
+import ctypes
+import time
 from threading import Lock
 
-LPC_CMDS=dict(IDLE = 0x00,
-              START = 0x01,
-              STOP = 0x02,
-              SET_TRACE_VARIABLE = 0x04,
-              GET_TRACE_VARIABLES = 0x05,
-              SET_FORCED_VARIABLE = 0x06,
-              GET_PLCID = 0x07)
-
-WAIT_DATA = 0x04
-
 LPC_STATUS=dict(STARTED = 0x01,
                 STOPPED = 0x02,
                 DEBUG = 0x03)
@@ -26,13 +19,27 @@
 
 class LPCProto:
     def __init__(self, port, rate, timeout):
+        # serialize access lock
+        self.TransactionLock = Lock()
         # open serial port
-        self.serialPort = serial.Serial( port, rate, timeout = timeout )
+#        self.serialPort = serial.Serial( port, rate, timeout = timeout )
+        # Debugging serial stuff
+        self._serialPort = serial.Serial( port, rate, timeout = timeout )
+        class myser:
+            def read(self_,cnt):
+                res = self._serialPort.read(cnt)
+                print "Recv :", map(hex,map(ord,res))
+                return res
+            def write(self_, str):
+                print "Send :", map(hex,map(ord,str))
+                self._serialPort.write(str)
+            def flush(self_):
+                self._serialPort.flush()
+        self.serialPort = myser()
+        # start with empty
         self.serialPort.flush()
         # handshake
-        self.HandleTransaction(LPCTransaction("IDLE"))
-        # serialize access lock
-        self.TransactionLock = Lock()
+        self.HandleTransaction(IDLETransaction())
     
     def HandleTransaction(self, transaction):
         self.TransactionLock.acquire()
@@ -50,12 +57,12 @@
         return current_plc_status, res
     
 class LPCTransaction:
-    def __init__(self, command, optdata):
-        self.Command =  LPC_CMDS[command]
-        self.OptData = optdata[:]
-        self.serialPort = None
+    def __init__(self, command, optdata = ""):
+        self.Command = command
+        self.OptData = optdata
+        self.pseudofile = None
         
-    def SetPseudoFile(pseudofile):
+    def SetPseudoFile(self, pseudofile):
         self.pseudofile = pseudofile
         
     def SendCommand(self):
@@ -63,26 +70,74 @@
         self.pseudofile.write(chr(self.Command))
         
     def GetCommandAck(self):
-        comm_status, current_plc_status = map(ord, self.pseudofile.read(2))
+        res = self.pseudofile.read(2)
+        if len(res) == 2:
+            comm_status, current_plc_status = map(ord, res)
+        else:
+            raise LPCError("LPC transaction error - controller did not ack order")
         # LPC returns command itself as an ack for command
         if(comm_status == self.Command):
             return current_plc_status
         return None 
         
-    def ExchangeData(self):
-        if self.Command & WAIT_DATA :
-            length = len(self.OptData)
-            # transform length into a byte string
-            # we presuppose endianess of LPC same as PC
-            lengthstr = ctypes.string_at(ctypes.pointer(ctypes.c_int(length)),4) 
-            self.pseudofile.write(lengthstr + self.OptData)
-            
-            lengthstr = self.pseudofile.read(4)
-            # transform a byte string into length 
-            length = ctypes.cast(ctypes.c_char_p(lengthstr), ctypes.POINTER(ctypes.c_int)).contents.value
-            return self.pseudofile.read(length)
-        return None
-        
+    def SendData(self):
+        length = len(self.OptData)
+        # transform length into a byte string
+        # we presuppose endianess of LPC same as PC
+        lengthstr = ctypes.string_at(ctypes.pointer(ctypes.c_int(length)),4) 
+        self.pseudofile.write(lengthstr + self.OptData)
+
+    def GetData(self):
+        lengthstr = self.pseudofile.read(4)
+        # transform a byte string into length 
+        length = ctypes.cast(ctypes.c_char_p(lengthstr), ctypes.POINTER(ctypes.c_int)).contents.value
+        return self.pseudofile.read(length)
+
+    def ExchangeData(self): 
+        pass
+
+class IDLETransaction(LPCTransaction):
+    def __init__(self):
+        LPCTransaction.__init__(self, 0x00)
+
+class STARTTransaction(LPCTransaction):
+    def __init__(self):
+        LPCTransaction.__init__(self, 0x01)
+    
+class STOPTransaction(LPCTransaction):
+    def __init__(self):
+        LPCTransaction.__init__(self, 0x02)
+
+class SET_TRACE_VARIABLETransaction(LPCTransaction):
+    def __init__(self, data):
+        LPCTransaction.__init__(self, 0x04, data)
+    ExchangeData = LPCTransaction.SendData
+
+class GET_TRACE_VARIABLETransaction(LPCTransaction):
+    def __init__(self):
+        LPCTransaction.__init__(self, 0x05)
+    ExchangeData = LPCTransaction.GetData
+
+class SET_FORCED_VARIABLETransaction(LPCTransaction):
+    def __init__(self, data):
+        LPCTransaction.__init__(self, 0x06, data)
+    ExchangeData = LPCTransaction.SendData
+
+class GET_PLCIDTransaction(LPCTransaction):
+    def __init__(self):
+        LPCTransaction.__init__(self, 0x07)
+    ExchangeData = LPCTransaction.GetData
+
 if __name__ == "__main__":
-    TestConnection = LPCProto()
-    
\ No newline at end of file
+    TestConnection = LPCProto(6,115200,2)
+    #TestConnection.HandleTransaction(GET_PLCIDTransaction())
+    TestConnection.HandleTransaction(STARTTransaction())
+    TestConnection.HandleTransaction(SET_TRACE_VARIABLETransaction(
+           "\x03\x00\x00\x00"))
+    TestConnection.HandleTransaction(STARTTransaction())
+    while True:
+        time.sleep(0.5)
+        TestConnection.HandleTransaction(SET_TRACE_VARIABLETransaction(
+           "\x01\x00\x00\x00"*31))
+   #print map(hex,map(ord,TestConnection.HandleTransaction(GET_TRACE_VARIABLETransaction())))
+    #TestConnection.HandleTransaction(STOPTransaction())