|
1 import os |
|
2 from xml.dom import minidom |
|
3 import cPickle |
|
4 |
|
5 from xmlclass import * |
|
6 |
|
7 from CFileEditor import CFileEditor |
|
8 from PLCControler import UndoBuffer, LOCATION_CONFNODE, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT |
|
9 |
|
10 CFileClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "cext_xsd.xsd")) |
|
11 |
|
12 TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", |
|
13 "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L", |
|
14 "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"} |
|
15 |
|
16 class CFile: |
|
17 XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?> |
|
18 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
|
19 <xsd:element name="CExtension"> |
|
20 <xsd:complexType> |
|
21 <xsd:attribute name="CFLAGS" type="xsd:string" use="required"/> |
|
22 <xsd:attribute name="LDFLAGS" type="xsd:string" use="required"/> |
|
23 </xsd:complexType> |
|
24 </xsd:element> |
|
25 </xsd:schema> |
|
26 """ |
|
27 EditorType = CFileEditor |
|
28 |
|
29 def __init__(self): |
|
30 filepath = self.CFileName() |
|
31 |
|
32 self.CFile = CFileClasses["CFile"]() |
|
33 if os.path.isfile(filepath): |
|
34 xmlfile = open(filepath, 'r') |
|
35 tree = minidom.parse(xmlfile) |
|
36 xmlfile.close() |
|
37 |
|
38 for child in tree.childNodes: |
|
39 if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "CFile": |
|
40 self.CFile.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"]) |
|
41 self.CreateCFileBuffer(True) |
|
42 else: |
|
43 self.CreateCFileBuffer(False) |
|
44 self.OnCTNSave() |
|
45 |
|
46 def GetIconName(self): |
|
47 return "Cfile" |
|
48 |
|
49 def CFileName(self): |
|
50 return os.path.join(self.CTNPath(), "cfile.xml") |
|
51 |
|
52 def GetBaseTypes(self): |
|
53 return self.GetCTRoot().GetBaseTypes() |
|
54 |
|
55 def GetDataTypes(self, basetypes = False, only_locatables = False): |
|
56 return self.GetCTRoot().GetDataTypes(basetypes=basetypes, only_locatables=only_locatables) |
|
57 |
|
58 def GetSizeOfType(self, type): |
|
59 return TYPECONVERSION.get(self.GetCTRoot().GetBaseType(type), None) |
|
60 |
|
61 def SetVariables(self, variables): |
|
62 self.CFile.variables.setvariable([]) |
|
63 for var in variables: |
|
64 variable = CFileClasses["variables_variable"]() |
|
65 variable.setname(var["Name"]) |
|
66 variable.settype(var["Type"]) |
|
67 variable.setclass(var["Class"]) |
|
68 self.CFile.variables.appendvariable(variable) |
|
69 |
|
70 def GetVariables(self): |
|
71 datas = [] |
|
72 for var in self.CFile.variables.getvariable(): |
|
73 datas.append({"Name" : var.getname(), "Type" : var.gettype(), "Class" : var.getclass()}) |
|
74 return datas |
|
75 |
|
76 def SetPartText(self, name, text): |
|
77 if name == "Includes": |
|
78 self.CFile.includes.settext(text) |
|
79 elif name == "Globals": |
|
80 self.CFile.globals.settext(text) |
|
81 elif name == "Init": |
|
82 self.CFile.initFunction.settext(text) |
|
83 elif name == "CleanUp": |
|
84 self.CFile.cleanUpFunction.settext(text) |
|
85 elif name == "Retrieve": |
|
86 self.CFile.retrieveFunction.settext(text) |
|
87 elif name == "Publish": |
|
88 self.CFile.publishFunction.settext(text) |
|
89 |
|
90 def GetPartText(self, name): |
|
91 if name == "Includes": |
|
92 return self.CFile.includes.gettext() |
|
93 elif name == "Globals": |
|
94 return self.CFile.globals.gettext() |
|
95 elif name == "Init": |
|
96 return self.CFile.initFunction.gettext() |
|
97 elif name == "CleanUp": |
|
98 return self.CFile.cleanUpFunction.gettext() |
|
99 elif name == "Retrieve": |
|
100 return self.CFile.retrieveFunction.gettext() |
|
101 elif name == "Publish": |
|
102 return self.CFile.publishFunction.gettext() |
|
103 return "" |
|
104 |
|
105 def CTNTestModified(self): |
|
106 return self.ChangesToSave or not self.CFileIsSaved() |
|
107 |
|
108 def OnCTNSave(self, from_project_path=None): |
|
109 filepath = self.CFileName() |
|
110 |
|
111 text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" |
|
112 extras = {"xmlns":"http://www.w3.org/2001/XMLSchema", |
|
113 "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", |
|
114 "xsi:schemaLocation" : "cext_xsd.xsd"} |
|
115 text += self.CFile.generateXMLText("CFile", 0, extras) |
|
116 |
|
117 xmlfile = open(filepath,"w") |
|
118 xmlfile.write(text.encode("utf-8")) |
|
119 xmlfile.close() |
|
120 |
|
121 self.MarkCFileAsSaved() |
|
122 return True |
|
123 |
|
124 def CTNGlobalInstances(self): |
|
125 current_location = self.GetCurrentLocation() |
|
126 return [("%s_%s" % ( |
|
127 variable.getname(),"_".join(map(str, current_location))), |
|
128 variable.gettype()) |
|
129 for variable in self.CFile.variables.variable] |
|
130 |
|
131 def CTNGenerate_C(self, buildpath, locations): |
|
132 """ |
|
133 Generate C code |
|
134 @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) |
|
135 @param locations: List of complete variables locations \ |
|
136 [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) |
|
137 "NAME" : name of the variable (generally "__IW0_1_2" style) |
|
138 "DIR" : direction "Q","I" or "M" |
|
139 "SIZE" : size "X", "B", "W", "D", "L" |
|
140 "LOC" : tuple of interger for IEC location (0,1,2,...) |
|
141 }, ...] |
|
142 @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND |
|
143 """ |
|
144 current_location = self.GetCurrentLocation() |
|
145 # define a unique name for the generated C file |
|
146 location_str = "_".join(map(str, current_location)) |
|
147 |
|
148 text = "/* Code generated by Beremiz c_ext confnode */\n\n" |
|
149 text += "#include <stdio.h>" |
|
150 |
|
151 # Adding includes |
|
152 text += "/* User includes */\n" |
|
153 text += self.CFile.includes.gettext() |
|
154 text += "\n" |
|
155 |
|
156 text += '#include "iec_types_all.h"' |
|
157 |
|
158 # Adding variables |
|
159 base_types = self.GetCTRoot().GetBaseTypes() |
|
160 config = self.GetCTRoot().GetProjectConfigNames()[0] |
|
161 text += "/* User variables reference */\n" |
|
162 for variable in self.CFile.variables.variable: |
|
163 var_infos = { |
|
164 "name": variable.getname(), |
|
165 "global": "%s__%s_%s" % (config.upper(), |
|
166 variable.getname().upper(), |
|
167 location_str), |
|
168 "type": "__IEC_%s_t" % variable.gettype()} |
|
169 text += "extern %(type)s %(global)s;\n" % var_infos |
|
170 text += "#define %(name)s %(global)s.value\n" % var_infos |
|
171 text += "\n" |
|
172 |
|
173 # Adding user global variables and routines |
|
174 text += "/* User internal user variables and routines */\n" |
|
175 text += self.CFile.globals.gettext() |
|
176 |
|
177 # Adding Beremiz confnode functions |
|
178 text += "/* Beremiz confnode functions */\n" |
|
179 text += "int __init_%s(int argc,char **argv)\n{\n"%location_str |
|
180 text += self.CFile.initFunction.gettext() |
|
181 text += " return 0;\n" |
|
182 text += "\n}\n\n" |
|
183 |
|
184 text += "void __cleanup_%s(void)\n{\n"%location_str |
|
185 text += self.CFile.cleanUpFunction.gettext() |
|
186 text += "\n}\n\n" |
|
187 |
|
188 text += "void __retrieve_%s(void)\n{\n"%location_str |
|
189 text += self.CFile.retrieveFunction.gettext() |
|
190 text += "\n}\n\n" |
|
191 |
|
192 text += "void __publish_%s(void)\n{\n"%location_str |
|
193 text += self.CFile.publishFunction.gettext() |
|
194 text += "\n}\n\n" |
|
195 |
|
196 Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str) |
|
197 cfile = open(Gen_Cfile_path,'w') |
|
198 cfile.write(text) |
|
199 cfile.close() |
|
200 |
|
201 matiec_flags = '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath()) |
|
202 |
|
203 return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_flags))],str(self.CExtension.getLDFLAGS()),True |
|
204 |
|
205 |
|
206 #------------------------------------------------------------------------------- |
|
207 # Current Buffering Management Functions |
|
208 #------------------------------------------------------------------------------- |
|
209 |
|
210 """ |
|
211 Return a copy of the cfile model |
|
212 """ |
|
213 def Copy(self, model): |
|
214 return cPickle.loads(cPickle.dumps(model)) |
|
215 |
|
216 def CreateCFileBuffer(self, saved): |
|
217 self.Buffering = False |
|
218 self.CFileBuffer = UndoBuffer(cPickle.dumps(self.CFile), saved) |
|
219 |
|
220 def BufferCFile(self): |
|
221 self.CFileBuffer.Buffering(cPickle.dumps(self.CFile)) |
|
222 |
|
223 def StartBuffering(self): |
|
224 self.Buffering = True |
|
225 |
|
226 def EndBuffering(self): |
|
227 if self.Buffering: |
|
228 self.CFileBuffer.Buffering(cPickle.dumps(self.CFile)) |
|
229 self.Buffering = False |
|
230 |
|
231 def MarkCFileAsSaved(self): |
|
232 self.EndBuffering() |
|
233 self.CFileBuffer.CurrentSaved() |
|
234 |
|
235 def CFileIsSaved(self): |
|
236 return self.CFileBuffer.IsCurrentSaved() and not self.Buffering |
|
237 |
|
238 def LoadPrevious(self): |
|
239 self.EndBuffering() |
|
240 self.CFile = cPickle.loads(self.CFileBuffer.Previous()) |
|
241 |
|
242 def LoadNext(self): |
|
243 self.CFile = cPickle.loads(self.CFileBuffer.Next()) |
|
244 |
|
245 def GetBufferState(self): |
|
246 first = self.CFileBuffer.IsFirst() and not self.Buffering |
|
247 last = self.CFileBuffer.IsLast() |
|
248 return not first, not last |
|
249 |