# HG changeset patch # User etisserant # Date 1189153144 -7200 # Node ID 9a0c535c3272f113dc549ba1766e5b1bcd526d79 # Parent bded6d31365c1cb538a506f5b93789b839dc5394 Pleliminary build process -- C code generation diff -r bded6d31365c -r 9a0c535c3272 Beremiz.py --- a/Beremiz.py Fri Sep 07 09:11:18 2007 +0200 +++ b/Beremiz.py Fri Sep 07 10:19:04 2007 +0200 @@ -47,23 +47,18 @@ def writelines(self, l): map(self.write, l) - def write(self, s): - if self.default_style != self.black_white: - self.output.SetDefaultStyle(self.black_white) - self.default_style = self.black_white + def write(self, s, style = None): + if not style : style=self.black_white + if self.default_style != style: + self.output.SetDefaultStyle(style) + self.default_style = style self.output.AppendText(s) def write_warning(self, s): - if self.default_style != self.red_white: - self.output.SetDefaultStyle(self.red_white) - self.default_style = self.red_white - self.output.AppendText(s) + self.write(s,self.red_white) def write_error(self, s): - if self.default_style != self.red_yellow: - self.output.SetDefaultStyle(self.red_yellow) - self.default_style = self.red_yellow - self.output.AppendText(s) + self.write(s,self.red_yellow) def flush(self): self.output.SetValue("") @@ -570,7 +565,8 @@ choicectrl.Append(choice) callback = self.GetChoiceCallBackFunction(choicectrl, element_path) choicectrl.Bind(wx.EVT_CHOICE, callback, id=id) - choicectrl.SetStringSelection(element_infos["value"]) + if element_infos["value"]: + choicectrl.SetStringSelection(element_infos["value"]) elif isinstance(element_infos["type"], types.DictType): boxsizer = wx.BoxSizer(wx.HORIZONTAL) if first: @@ -582,7 +578,8 @@ pos=wx.Point(0, 0), size=wx.Size(100, 17), style=0) boxsizer.AddWindow(statictext, 0, border=0, flag=wx.TOP|wx.LEFT|wx.BOTTOM) id = wx.NewId() - min = max = -1 + min = -sys.maxint-1 + max = sys.maxint if "min" in element_infos["type"]: min = element_infos["type"]["min"] if "max" in element_infos["type"]: @@ -636,7 +633,7 @@ def OnNewProjectMenu(self, event): defaultpath = self.PluginRoot.GetProjectPath() - if defaultpath == "": + if not defaultpath: defaultpath = os.getcwd() dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON) if dialog.ShowModal() == wx.ID_OK: diff -r bded6d31365c -r 9a0c535c3272 plugger.py --- a/plugger.py Fri Sep 07 09:11:18 2007 +0200 +++ b/plugger.py Fri Sep 07 10:19:04 2007 +0200 @@ -7,6 +7,7 @@ import types import shutil from xml.dom import minidom +import wx #Quick hack to be able to find Beremiz IEC tools. Should be config params. base_folder = os.path.split(sys.path[0])[0] @@ -136,11 +137,15 @@ Generate C code @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) @param locations: List of complete variables locations \ - [(IEC_loc, IEC_Direction, IEC_Type, Name)]\ - ex: [((0,0,4,5),'I','STRING','__IX_0_0_4_5'),...] + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND """ - logger.write_warning(".".join(map(lambda x:str(x), current_location)) + " -> Nothing yo do") + logger.write_warning(".".join(map(lambda x:str(x), current_location)) + " -> Nothing yo do\n") return [],"" def _Generate_C(self, buildpath, current_location, locations, logger): @@ -158,7 +163,7 @@ # but update location (add curent IEC channel at the end) new_location, # filter locations that start with current IEC location - [ (l,d,t,n) for l,d,t,n in locations if l[0:len(new_location)] == new_location ], + [loc for loc in locations if loc["LOC"][0:len(new_location)] == new_location ], #propagete logger logger) # stack the result @@ -377,6 +382,7 @@ from PLCOpenEditor import PLCOpenEditor, ProjectDialog from TextViewer import TextViewer from plcopen.structures import IEC_KEYWORDS +import re class PluginsRoot(PlugTemplate): """ @@ -504,8 +510,8 @@ # Create Controler for PLCOpen program self.PLCManager = PLCControler() - self.PLCManager.CreateNewProject(PLCParams.pop("projectName")) - self.PLCManager.SetProjectProperties(properties = PLCParams) + self.PLCManager.CreateNewProject(values.pop("projectName")) + self.PLCManager.SetProjectProperties(properties = values) # Change XSD into class members self._AddParamsMembers() self.PluggedChilds = {} @@ -587,15 +593,15 @@ result = self.PLCManager.GenerateProgram(plc_file) if not result: # Failed ! - logger.write_error("Error : ST/IL/SFC code generator returned %d"%result) + logger.write_error("Error : ST/IL/SFC code generator returned %d\n"%result) return False logger.write("Compiling ST Program in to C Program...\n") # Now compile IEC code into many C files # files are listed to stdout, and errors to stderr. - status, result, err_result = logger.LogCommand("%s %s -I %s %s"%(iec2cc_path, plc_file, ieclib_path, self.TargetDir)) + status, result, err_result = logger.LogCommand("%s %s -I %s %s"%(iec2cc_path, plc_file, ieclib_path, buildpath)) if status: # Failed ! - logger.write_error("Error : IEC to C compiler returned %d"%status) + logger.write_error("Error : IEC to C compiler returned %d\n"%status) return False # Now extract C files of stdout C_files = result.splitlines() @@ -641,14 +647,14 @@ if not os.path.exists(buildpath): os.mkdir(buildpath) - logger.write("Start build in %s" % buildpath) + logger.write("Start build in %s\n" % buildpath) # Generate SoftPLC code if not self._Generate_SoftPLC(logger): - logger.write_error("SoftPLC code generation failed !") + logger.write_error("SoftPLC code generation failed !\n") return False - logger.write("SoftPLC code generation successfull") + logger.write("SoftPLC code generation successfull\n") # Generate C code and compilation params from plugin hierarchy try: @@ -658,18 +664,18 @@ self.PLCGeneratedLocatedVars, logger) except Exception, msg: - logger.write_error("Plugins code generation Failed !") + logger.write_error("Plugins code generation Failed !\n") logger.write_error(str(msg)) return False - logger.write_error("Plugins code generation successfull") + logger.write("Plugins code generation successfull\n") # Compile the resulting code into object files. for CFile, CFLAG in CFilesAndCFLAGS: - print CFile,CFLAG + logger.write(str((CFile,CFLAG))) # Link object files into something that can be executed on target - print LDFLAGS + logger.write(LDFLAGS) def _showIECcode(self, logger): plc_file = self._getIECcodepath() @@ -687,12 +693,18 @@ def _EditPLC(self, logger): if not self.PLCEditor: - self.PLCEditor = PLCOpenEditor(self, self.PLCManager) + self.PLCEditor = PLCOpenEditor(self.AppFrame, self.PLCManager) self.PLCEditor.RefreshProjectTree() self.PLCEditor.RefreshFileMenu() self.PLCEditor.RefreshEditMenu() self.PLCEditor.RefreshToolBar() self.PLCEditor.Show() - PluginMethods = [("Build",_build), ("Clean",None), ("Run",None), ("EditPLC",None), ("Show IEC code",_showIECcode)] - + def _Clean(self, logger): + logger.write_error("Not impl\n") + + def _Run(self, logger): + logger.write_error("Not impl\n") + + PluginMethods = [("EditPLC",_EditPLC), ("Build",_build), ("Clean",_Clean), ("Run",_Run), ("Show IEC code",_showIECcode)] + diff -r bded6d31365c -r 9a0c535c3272 plugins/canfestival/canfestival.py --- a/plugins/canfestival/canfestival.py Fri Sep 07 09:11:18 2007 +0200 +++ b/plugins/canfestival/canfestival.py Fri Sep 07 10:19:04 2007 +0200 @@ -56,11 +56,18 @@ Generate C code @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) @param locations: List of complete variables locations \ - [(IEC_loc, IEC_Direction IEC_Type, Name)]\ - ex: [((0,0,4,5),'I','X','__IX_0_0_4_5'),...] + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND """ + # define a unique name for the generated C file prefix = "_".join(map(lambda x:str(x), current_location)) Gen_OD_path = os.path.join(buildpath, prefix + "_OD.c" ) + # Create a new copy of the model with DCF loaded with PDO mappings for desired location master = config_utils.GenerateConciseDCF(locations, current_location, self) res = gen_cfile.GenerateFile(Gen_OD_path, master) if res : @@ -82,25 +89,6 @@ PlugChildsTypes = [("CanOpenNode",_NodeListPlug)] def PlugGenerate_C(self, buildpath, current_location, locations): - """ - Generate C code - @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) - @param locations: List of complete variables locations \ - [(IEC_loc, IEC_Direction IEC_Type, Name)]\ - ex: [((0,0,4,5),'I','X','__IX_0_0_4_5'),...] - """ - prefix = "_".join(map(lambda x:str(x), current_location)) - Gen_OD_path = os.path.join(buildpath, prefix + "_OD.c" ) - master = config_utils.GenerateConciseDCF(locations, self) - res = gen_cfile.GenerateFile(Gen_OD_path, master) - if not res: - s = str(self.BaseParams.BusId)+"_IN(){}\n" - s += "CanOpen(str(\""+self.CanFestivalNode.CAN_Device+"\")" - f = file(filepath, 'a') - f.write(s) - else: - pass # error - return [],"" diff -r bded6d31365c -r 9a0c535c3272 plugins/canfestival/config_utils.py --- a/plugins/canfestival/config_utils.py Fri Sep 07 09:11:18 2007 +0200 +++ b/plugins/canfestival/config_utils.py Fri Sep 07 10:19:04 2007 +0200 @@ -139,7 +139,20 @@ return ListCobIDAvailable.pop(0) -def GenerateConciseDCF(locations, busname, nodelist): +def GenerateConciseDCF(locations, current_location, nodelist): + """ + Fills a CanFestival network editor model, with DCF with requested PDO mappings. + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @param nodelist: CanFestival network editor model + @return: a modified copy of the given CanFestival network editor model + """ + global DictLocations, DictCobID, DictLocationsNotMapped, ListCobIDAvailable, SlavesPdoNumber, DefaultTransmitTypeSlave DictLocations = {} @@ -187,45 +200,46 @@ ListCobIDAvailable.remove(pdo_cobid) # Get list of locations check if exists and mappables -> put them in DictLocations - for locationtype, name in locations: - if name in DictLocations.keys(): + for location in locations: + locationtype = location["IEC_TYPE"] + name = location["NAME"] + if name in DictLocations: if DictLocations[name]["type"] != DicoTypes[locationtype]: raise ValueError, "Conflict type for location \"%s\"" % name else: - loc = [i for i in name.split("_") if len(i) > 0] - if len(loc) not in (4, 5): - continue - - prefix = loc[0][0] - - # Extract and check busname - if loc[0][1].isdigit(): - sizelocation = "" - busnamelocation = int(loc[0][1:]) - else: - sizelocation = loc[0][1] - busnamelocation = int(loc[0][2:]) - if busnamelocation != busname: - continue # A ne pas remplacer par un message d'erreur + #get only the part of the location that concern this node + loc = location["LOC"][len(current_location):] + # loc correspond to (ID, INDEX, SUBINDEX [,BIT]) + if len(loc) not in (3, 4): + raise ValueError, "Bad location size" + + direction = location["DIR"] + + sizelocation = location["SIZE"] # Extract and check nodeid - nodeid = int(loc[1]) + nodeid, index, subindex = loc[:3] + + # Check Id is in slave node list if nodeid not in nodelist.SlaveNodes.keys(): - continue + raise ValueError, "Non existing node ID : %d (variable %s)" % (nodeid,name) + + # Get the model for this node (made from EDS) node = nodelist.SlaveNodes[nodeid]["Node"] # Extract and check index and subindex - index = int(loc[2]) - subindex = int(loc[3]) if not node.IsEntry(index, subindex): - continue + raise ValueError, "No such index/subindex (%x,%x) in ID : %d (variable %s)" % (index,subindex,nodeid,name) + + #Get the entry info subentry_infos = node.GetSubentryInfos(index, subindex) + # If a PDO mappable if subentry_infos and subentry_infos["pdo"]: - if sizelocation == "X" and len(loc) > 4: + if sizelocation == "X" and len(loc) > 3: numbit = loc[4] - elif sizelocation != "X" and len(loc) > 4: - continue + elif sizelocation != "X" and len(loc) > 3: + raise ValueError, "Cannot set bit offset for non bool '%s' variable (ID:%d,Idx:%x,sIdx:%x))" % (name,nodeid,index,subindex) else: numbit = None @@ -235,10 +249,12 @@ raise ValueError, "Invalid type for location \"%s\"" % name typeinfos = node.GetEntryInfos(locationtype) - DictLocations[name] = {"type":locationtype, "pdotype":SlavePDOType[prefix], + DictLocations[name] = {"type":locationtype, "pdotype":SlavePDOType[direction], "nodeid": nodeid, "index": index,"subindex": subindex, "bit": numbit, "size": typeinfos["size"], "busname": busname, "sizelocation": sizelocation} - + else: + raise ValueError, "Not PDO mappable variable : '%s' (ID:%d,Idx:%x,sIdx:%x))" % (name,nodeid,index,subindex) + # Create DictCobID with variables already mapped and add them in DictValidLocations for name, locationinfos in DictLocations.items(): node = nodelist.SlaveNodes[locationinfos["nodeid"]]["Node"]