Revamped LPC connector and toolchain
authoredouard
Fri, 11 Dec 2009 16:39:20 +0100
changeset 508 73ecb803d8af
parent 507 bf6f623d7450
child 509 aa5645a25d64
Revamped LPC connector and toolchain
connectors/LPC/LPCObject.py
connectors/LPC/LPCProto.py
connectors/LPC/__init__.py
targets/LPC/__init__.py
targets/XSD_toolchain_makefile
targets/toolchain_makefile.py
--- a/connectors/LPC/LPCObject.py	Fri Dec 11 13:04:22 2009 +0100
+++ b/connectors/LPC/LPCObject.py	Fri Dec 11 16:39:20 2009 +0100
@@ -22,35 +22,60 @@
 #License along with this library; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-from threading import Timer, Thread, Lock
 import ctypes, os, commands, types, sys
-import traceback
 from LPCProto import *
 
 class LPCObject():
-    def __init__(self,pluginsroot):
-        self.PLCStatus = "Stopped"
+    def __init__(self,pluginsroot, location):
+        self.PLCStatus = "Disconnected"
         self.pluginsroot = pluginsroot
         self.PLCprint = pluginsroot.logger.write
-        self.SerialConnection = None
-        self.StorageConnection = None
         self._Idxs = []
-        
-    def HandleSerialTransaction(self, transaction):
-        if self.SerialConnection is None:
+        self.UpdateLocation(location)
+
+    def UpdateLocation(self, location):
+        # Is that a comport ?
+        if len(location) == 5 and\
+           location.startswith("COM") and \
+           location[3].isdigit() and \
+           location[4]==":" :
+            self.StorageConnection = None
             try:
-                self.SerialConnection = LPCProto(6,115200,2)
+                comport = int(location[3]) - 1
+                self.SerialConnection = LPCProto(comport,#number
+                                                 115200, #speed
+                                                 2)      #timeout
+                # This will update status
+                self.HandleSerialTransaction(IDLETransaction())
             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.PLCStatus = "Disconnected"
+        # or a drive unit ?
+        elif len(location)==2 and \
+             location[0].isalpha() and \
+             location[1] == ':' :
             self.SerialConnection = None
-            return "Disconnected", res
+            if os.path.exist(location):
+                self.StorageConnection = location
+                self.PLCStatus = "Stopped"
+            else:
+                self.pluginsroot.logger.write_error("Drive "+
+                                                    location+
+                                                    " do not exist !\n")
+                self.StorageConnection = None
+                self.PLCStatus = "Disconnected"
+        
+    def HandleSerialTransaction(self, transaction):
+        if self.SerialConnection is not None:
+            try:
+                self.PLCStatus, res = self.SerialConnection.HandleTransaction(transaction)
+                return res
+            except LPCError,e:
+                self.pluginsroot.logger.write_error(str(e)+"\n")
+                self.SerialConnection = None
+                self.PLCStatus = "Disconnected"
+                return None
 
     def StartPLC(self, debug=False):
         PLCprint("StartPLC")
@@ -64,14 +89,14 @@
         pass
 
     def GetPLCstatus(self):
-        status,data = self.HandleSerialTransaction(IDLETransaction())
-        return status
+        self.HandleSerialTransaction(IDLETransaction())
+        return self.PLCStatus
     
     def NewPLC(self, md5sum, data, extrafiles):
         pass
 
     def MatchMD5(self, MD5):
-        status,data = self.HandleSerialTransaction(PLCIDTransaction())
+        data = self.HandleSerialTransaction(PLCIDTransaction())
         return data == MD5
 
     class IEC_STRING(ctypes.Structure):
@@ -104,12 +129,6 @@
                       } 
 
     def SetTraceVariablesList(self, idxs):
-        self._Idxs = idxs[:]
-        status,data = self.HandleSerialTransaction(
-               SET_TRACE_VARIABLETransaction(
-                     ''.join(map(chr,idx))))
-
-    def SetTraceVariablesList(self, idxs):
         """
         Call ctype imported function to append 
         these indexes to registred variables in PLC debugger
@@ -132,7 +151,7 @@
                     buff += idxstr + forced_type_size_str + forcestr
                 else:
                     buff += idxstr + chr(0)
-            status,data = self.HandleSerialTransaction(
+            data = self.HandleSerialTransaction(
                    SET_TRACE_VARIABLETransaction(buff))
         else:
             self._Idxs =  []
@@ -141,33 +160,32 @@
         """
         Return a list of variables, corresponding to the list of required idx
         """
-        if self.PLCStatus == "Started":
-            res=[]
-            tick = ctypes.c_uint32()
-            size = ctypes.c_uint32()
-            buffer = ctypes.c_void_p()
-            offset = 0
-            if self.PLClibraryLock.acquire(False) and \
-               self._GetDebugData(ctypes.byref(tick),ctypes.byref(size),ctypes.byref(buffer)) == 0 :
-                if size.value:
-                    for idx, iectype, forced in self._Idxs:
-                        cursor = ctypes.c_void_p(buffer.value + offset)
-                        c_type,unpack_func, pack_func = self.TypeTranslator.get(iectype, (None,None,None))
-                        if c_type is not None and offset < size:
-                            res.append(unpack_func(ctypes.cast(cursor,
-                                                               ctypes.POINTER(c_type)).contents))
-                            offset += ctypes.sizeof(c_type)
-                        else:
-                            if c_type is None:
-                                PLCprint("Debug error - " + iectype + " not supported !")
-                            if offset >= size:
-                                PLCprint("Debug error - buffer too small !")
-                            break
-                self._FreeDebugData()
-                self.PLClibraryLock.release()
-            if offset and offset == size.value:
+        offset = 0
+        strbuf = self.HandleSerialTransaction(
+                                     GET_TRACE_VARIABLETransaction())
+        size = len(strbuf) - 4
+        if size > 0 and self.PLCStatus == "Started":
+            tick = ctypes.cast(
+                    ctypes.c_char_p(strbuf[:4]),
+                    ctypes.POINTER(ctypes.c_int)).contents
+            buffer = ctypes.cast(
+                      ctypes.c_char_p(strbuf[4:]),
+                      ctypes.c_void_p)
+            for idx, iectype, forced in self._Idxs:
+                cursor = ctypes.c_void_p(buffer.value + offset)
+                c_type,unpack_func, pack_func = self.TypeTranslator.get(iectype, (None,None,None))
+                if c_type is not None and offset < size:
+                    res.append(unpack_func(ctypes.cast(cursor,
+                                                       ctypes.POINTER(c_type)).contents))
+                    offset += ctypes.sizeof(c_type)
+                else:
+                    if c_type is None:
+                        PLCprint("Debug error - " + iectype + " not supported !")
+                    if offset >= size:
+                        PLCprint("Debug error - buffer too small !")
+                    break
+            if offset and offset == size:
                 return self.PLCStatus, tick.value, res
-            elif size.value:
-                PLCprint("Debug error - wrong buffer unpack !")
+            PLCprint("Debug error - wrong buffer unpack !")
         return self.PLCStatus, None, None
 
--- a/connectors/LPC/LPCProto.py	Fri Dec 11 13:04:22 2009 +0100
+++ b/connectors/LPC/LPCProto.py	Fri Dec 11 16:39:20 2009 +0100
@@ -6,9 +6,8 @@
 
 MAX_PACKET_SIZE=64
 
-LPC_STATUS=dict(STARTED = 0x01,
-                STOPPED = 0x02,
-                DEBUG = 0x03)
+LPC_STATUS={0x01 : "Started",
+            0x02 : "Stopped"}
 
 class LPCError(exceptions.Exception):
         """Exception class"""
@@ -40,8 +39,6 @@
         self.serialPort = myser()
         # start with empty
         self.serialPort.flush()
-        # handshake
-        self.HandleTransaction(IDLETransaction())
     
     def HandleTransaction(self, transaction):
         self.TransactionLock.acquire()
@@ -56,7 +53,7 @@
                 raise LPCError("LPC transaction error - controller did not answer as expected")
         finally:
             self.TransactionLock.release()
-        return current_plc_status, res
+        return LPC_STATUS.get(current_plc_status,"Broken"), res
     
 class LPCTransaction:
     def __init__(self, command, optdata = ""):
@@ -133,11 +130,6 @@
         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)
@@ -150,17 +142,18 @@
 #    TestConnection.HandleTransaction(SET_TRACE_VARIABLETransaction(
 #           "\x03\x00\x00\x00"*200))
 #    TestConnection.HandleTransaction(STARTTransaction())
-    TestConnection.HandleTransaction(SET_TRACE_VARIABLETransaction(
-       "\x01\x00\x00\x00"+
-       "\x04"+
-       "\x01\x02\x02\x04"+
-       "\x01\x00\x00\x00"+
-       "\x08"+
-       "\x01\x02\x02\x04"+
-       "\x01\x02\x02\x04"+
-       "\x01\x00\x00\x00"+
-       "\x04"+
-       "\x01\x02\x02\x04"))
+    while True:
+        TestConnection.HandleTransaction(SET_TRACE_VARIABLETransaction(
+           "\x01\x00\x00\x00"+
+           "\x04"+
+           "\x01\x02\x02\x04"+
+           "\x01\x00\x00\x00"+
+           "\x08"+
+           "\x01\x02\x02\x04"+
+           "\x01\x02\x02\x04"+
+           "\x01\x00\x00\x00"+
+           "\x04"+
+           "\x01\x02\x02\x04"))
     #status,res = TestConnection.HandleTransaction(GET_TRACE_VARIABLETransaction())
     #print len(res)
     #print "GOT : ", map(hex, map(ord, res))
--- a/connectors/LPC/__init__.py	Fri Dec 11 13:04:22 2009 +0100
+++ b/connectors/LPC/__init__.py	Fri Dec 11 16:39:20 2009 +0100
@@ -18,15 +18,20 @@
 #You should have received a copy of the GNU General Public
 #License along with this library; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-import traceback
 import LPCObject
 
+permanant_connector = None
 
 def LPC_connector_factory(uri, pluginsroot):
     """
     This returns the connector to LPC style PLCobject
     """
-    pluginsroot.logger.write(_("Connecting to URI : %s\n")%uri)
-    return LPCObject()
+    global permanant_connector
+    if permanant_connector is None:
+        permanant_connector  = LPCObject(pluginsroot,location)
+    else:
+        servicetype, location = uri.split("://")
+        permanant_connector.UpdateLocation(location)
+    return permanant_connector
     
 
--- a/targets/LPC/__init__.py	Fri Dec 11 13:04:22 2009 +0100
+++ b/targets/LPC/__init__.py	Fri Dec 11 16:39:20 2009 +0100
@@ -3,5 +3,3 @@
 class LPC_target(toolchain_makefile):
     extension = ".ld"
     DebugEnabled = False
-    def getBuilderLDFLAGS(self):
-        return toolchain_makefile.getBuilderLDFLAGS(self)
--- a/targets/XSD_toolchain_makefile	Fri Dec 11 13:04:22 2009 +0100
+++ b/targets/XSD_toolchain_makefile	Fri Dec 11 16:39:20 2009 +0100
@@ -1,6 +1,6 @@
 
           <xsd:attribute name="BuildPath" type="xsd:string" use="optional" default=""/>
           <xsd:attribute name="Command" type="xsd:string" use="optional" default="make -C"/>
-          <xsd:attribute name="Arguments" type="xsd:string" use="optional" default="BEREMIZSRC=%(src)s BEREMIZCFLAGS=%(cflags)s USE_BEREMIZ=1 --quiet"/>
+          <xsd:attribute name="Arguments" type="xsd:string" use="optional" default="BEREMIZSRC=%(src)s BEREMIZCFLAGS=%(cflags)s MD5=%(md5)s USE_BEREMIZ=1 --quiet"/>
           <xsd:attribute name="Rule" type="xsd:string" use="optional" default="all"/>
           
--- a/targets/toolchain_makefile.py	Fri Dec 11 13:04:22 2009 +0100
+++ b/targets/toolchain_makefile.py	Fri Dec 11 16:39:20 2009 +0100
@@ -5,26 +5,63 @@
 
 includes_re =  re.compile('\s*#include\s*["<]([^">]*)[">].*')
 
-class toolchain_makefile(toolchain_gcc):
-    """
-    This abstract class contains GCC specific code.
-    It cannot be used as this and should be inherited in a target specific
-    class such as target_linux or target_win32
-    """
+class toolchain_makefile():
+    def __init__(self, PluginsRootInstance):
+        self.PluginsRootInstance = PluginsRootInstance
+        self.md5key = None 
+        self.buildpath = None
+        self.SetBuildPath(self.PluginsRootInstance._getBuildPath())
+
+    def getTarget(self):
+        target = self.PluginsRootInstance.BeremizRoot.getTargetType()
+        if target.getcontent() is None:
+            target = self.PluginsRootInstance.GetDefaultTarget()
+        return target
+
+    def SetBuildPath(self, buildpath):
+        self.buildpath = buildpath
+        self.exe_path = os.path.join(self.buildpath, "ArmPLC_rom.bin")
+        self.md5_path = os.path.join(self.buildpath, "ArmPLC.md5")
+
+    def GetBinaryCode(self):
+        try:
+            return open(self.exe_path, "rb").read()
+        except Exception, e:
+            return None
+
+    def _GetMD5FileName(self):
+        return os.path.join(self.buildpath, "lastbuildPLC.md5")
+
+    def GetBinaryCodeMD5(self):
+        if self.md5key is not None:
+            return self.md5key
+        else:
+            try:
+                return open(self._GetMD5FileName(), "r").read()
+            except Exception, e:
+                return None
 
     def build(self):
         srcfiles= []
         cflags = []
         for Location, CFilesAndCFLAGS, DoCalls in self.PluginsRootInstance.LocationCFilesAndCFLAGS:
-            # Get CFiles list to give it to makefile 
+            wholesrcdata = "" 
+            # Get CFiles list to give it to makefile
             for CFile, CFLAGS in CFilesAndCFLAGS:
                 CFileName = os.path.basename(CFile)
+                wholesrcdata += open(CFile, "r").read()
                 srcfiles.append(CFileName)
                 if CFLAGS not in cflags:
                     cflags.append(CFLAGS)
                     
+            self.md5key = hashlib.md5(wholesrcdata).hexdigest()
+            # Store new PLC filename based on md5 key
+            f = open(self._GetMD5FileName(), "w")
+            f.write(self.md5key)
+            f.close()
         beremizcommand = {"src": ' '.join(srcfiles),
-                          "cflags": ' '.join(cflags)
+                          "cflags": ' '.join(cflags),
+                          "md5": self.md5key
                          }
         
         target = self.getTarget().getcontent()["value"]