2 Generate address space c++ code from xml file specification 7 import xml.etree.ElementTree
as ET
9 from IPython
import embed
11 import generate_model
as gm
15 NeedConstructor = [
"RelativePathElement",
"OpenSecureChannelParameters",
"UserIdentityToken",
"RequestHeader",
"ResponseHeader",
"ReadParameters",
"UserIdentityToken",
"BrowseDescription",
"ReferenceDescription",
"CreateSubscriptionParameters",
"SubscriptionData",
"NotificationMessage",
"PublishResult",
"PublishResult",
"NotificationMessage",
"SetPublishingModeParameters"]
16 IgnoredEnums = [
"IdType",
"NodeIdType"]
18 NoSplitStruct = [
"GetEndpointsResponse",
"CloseSessionRequest",
"AddNodesResponse",
"BrowseResponse",
"HistoryReadResponse",
"HistoryUpdateResponse",
"RegisterServerResponse",
"CloseSecureChannelRequest",
"CloseSecureChannelResponse",
"CloseSessionRequest",
"CloseSessionResponse",
"UnregisterNodesResponse",
"MonitoredItemModifyRequest",
"MonitoredItemsCreateRequest",
"ReadResponse",
"WriteResponse",
"TranslateBrowsePathsToNodeIdsResponse",
"DeleteSubscriptionsResponse",
"DeleteMonitoredItemsResponse",
"PublishRequest",
"CreateMonitoredItemsResponse",
"DeleteMonitoredItemsResponse",
"ServiceFault",
"AddReferencesRequest",
"AddReferencesResponse",
"ModifyMonitoredItemsResponse",
"CallResponse",
"RepublishResponse",
"DeleteSubscriptionsRequest",
"DeleteSubscriptionsResponse",
"DeleteNodesRequest",
"DeleteNodesResponse"]
19 OverrideTypes = {
"AttributeId":
"AttributeId",
"ResultMask":
"BrowseResultMask",
"NodeClassMask":
"NodeClass",
"AccessLevel":
"VariableAccessLevel",
"UserAccessLevel":
"VariableAccessLevel",
"NotificationData":
"NotificationData"}
20 OverrideStructTypeName = {
"CreateSubscriptionResult":
"SubscriptionData",
"SetPublishingModeParameters":
"PublishingModeParameters",
"SetPublishingModeResult":
"PublishingModeResult",
"CreateMonitoredItemsParameters":
"MonitoredItemsParameters"}
21 OverrideNameInStruct = {
"CreateSubscriptionResponse": {
"Parameters":
"Data"},
"SetPublishingModeResponse": {
"Parameters":
"Result"}}
22 OverrideTypeInStruct = {
"ActivateSessionParameters": {
"UserIdentityToken":
"UserIdentifyToken"},
"MonitoringParameters": {
"Filter":
"MonitoringFilter"},
"MonitoredItemCreateResult": {
"FilterResult":
"MonitoringFilter"}}
23 OverrideNames = {
"RequestHeader":
"Header",
"ResponseHeader":
"Header",
"StatusCode":
"Status",
"NodesToRead":
"AttributesToRead"}
63 'ApplicationDescription',
70 'EndpointDescription',
71 'GetEndpointsRequest',
72 'GetEndpointsParameters',
73 'GetEndpointsResponse',
82 'SignedSoftwareCertificate',
84 'CreateSessionRequest',
85 'CreateSessionParameters',
86 'CreateSessionResponse',
87 'CreateSessionResult',
93 'ActivateSessionRequest',
94 'ActivateSessionParameters',
95 'ActivateSessionResponse',
96 'ActivateSessionResult',
118 'DeleteNodesRequest',
119 'DeleteNodesResponse',
210 'MonitoringParameters',
211 'MonitoredItemCreateRequest',
212 'MonitoredItemCreateResult',
213 'MonitoredItemsParameters',
214 'CreateMonitoredItemsRequest',
215 'CreateMonitoredItemsResponse',
224 'DeleteMonitoredItemsParameters',
225 'DeleteMonitoredItemsRequest',
226 'DeleteMonitoredItemsResponse',
227 'CreateSubscriptionRequest',
228 'CreateSubscriptionParameters',
230 'CreateSubscriptionResponse',
231 'ModifySubscriptionRequest',
232 'ModifySubscriptionParameters',
233 'ModifySubscriptionResult',
234 'ModifySubscriptionResponse',
235 'SetPublishingModeRequest',
236 'PublishingModeParameters',
237 'SetPublishingModeResponse',
238 'PublishingModeResult',
239 'NotificationMessage',
247 'SubscriptionAcknowledgement',
251 'RepublishParameters',
257 'DeleteSubscriptionsRequest',
258 'DeleteSubscriptionsResponse',
290 def reorder_structs(model):
291 types = IgnoredEnums + [
"Bit",
"Char",
"CharArray",
"Guid",
"SByte",
"Int8",
"Int16",
"Int32",
"Int64",
"UInt8",
"UInt16",
"UInt32",
"UInt64",
"DateTime",
"Boolean",
"Double",
"Float",
"ByteString",
"Byte",
"StatusCode",
"DiagnosticInfo",
"String",
"AttributeId"] + [enum.name
for enum
in model.enums] + [
"VariableAccessLevel"]
294 for s
in model.structs:
299 if f.uatype
not in types:
300 if f.uatype
in waiting.keys():
301 waiting[f.uatype].append(s)
302 s.waitingfor.append(f.uatype)
304 waiting[f.uatype] = [s]
305 s.waitingfor.append(f.uatype)
309 waitings = waiting.pop(s.name,
None)
312 s2.waitingfor.remove(s.name)
313 if not s2.waitingfor:
314 newstructs.append(s2)
315 if len(model.structs) != len(newstructs):
316 print(
"Error while reordering structs, some structs could not be reinserted, had {} structs, we now have {} structs".
format(len(model.structs), len(newstructs)))
317 s1 =
set(model.structs)
320 print(
"Variant" in types)
322 print(
"{} is waiting for: {}".
format(s, s.waitingfor))
325 model.structs = newstructs
328 def override_types(model):
329 for struct
in model.structs:
330 for field
in struct.fields:
331 if field.name
in OverrideTypes.keys():
332 field.uatype = OverrideTypes[field.name]
334 if struct.name
in OverrideNameInStruct.keys():
335 if field.name
in OverrideNameInStruct[struct.name].keys():
336 field.name = OverrideNameInStruct[struct.name][field.name]
338 if struct.name
in OverrideTypeInStruct.keys():
339 if field.name
in OverrideTypeInStruct[struct.name].keys():
340 field.uatype = OverrideTypeInStruct[struct.name][field.name]
342 if field.uatype
in OverrideStructTypeName.keys():
343 field.uatype = OverrideStructTypeName[field.uatype]
345 if struct.name
in OverrideStructTypeName.keys():
346 struct.name = OverrideStructTypeName[struct.name]
349 class CodeGenerator(object):
350 def __init__(self, model, h_path, enum_path, size_path, ser_path, deser_path, const_path):
353 self.enum_path = enum_path
354 self.rawsize_path = size_path
355 self.serialize_path = ser_path
356 self.deserialize_path = deser_path
357 self.constructors_path = const_path
364 print(
"Generating: ", self.h_path)
365 self.h_file = open(self.h_path,
"w")
366 print(
"Generating: ", self.enum_path)
367 self.enum_file = open(self.enum_path,
"w")
368 print(
"Generating: ", self.rawsize_path)
369 self.rawsize_file = open(self.rawsize_path,
"w")
370 print(
"Generating: ", self.serialize_path)
371 self.serialize_file = open(self.serialize_path,
"w")
372 print(
"Generating: ", self.deserialize_path)
373 self.deserialize_file = open(self.deserialize_path,
"w")
374 print(
"Generating: ", self.constructors_path)
375 self.constructors_file = open(self.constructors_path,
"w")
378 self.make_header_enum()
379 self.make_header_rawsize()
380 self.make_header_serialize()
381 self.make_header_deserialize()
382 self.make_header_constructors()
384 for enum
in self.model.enums:
385 if not enum.name
in IgnoredEnums:
386 self.make_enum_h(enum)
387 self.make_struct_ser(enum)
388 for struct
in self.model.structs:
389 self.rename_fields(struct)
390 if struct.name
in NeedConstructor:
391 struct.needconstructor =
True 393 if not struct.name
in EnabledStructs:
394 self.write_h(
"\n/* DISABLED")
395 self.write_size(
"\n/* DISABLED")
396 self.write_ser(
"\n/* DISABLED")
397 self.write_deser(
"\n/* DISABLED")
398 if struct.needconstructor:
399 self.write_const(
"\n/* DISABLED")
400 self.make_struct_h(struct)
401 self.make_struct_ser(struct)
403 self.make_request_constructors(struct)
404 if not struct.name
in EnabledStructs:
406 self.write_size(
"*/")
408 self.write_deser(
"*/")
409 if struct.needconstructor:
410 self.write_const(
"*/")
413 self.make_footer_enum()
414 self.make_footer_rawsize()
415 self.make_footer_serialize()
416 self.make_footer_deserialize()
417 self.make_footer_constructors()
419 def rename_fields(self, struct):
421 for field
in struct.fields:
422 if field.name
in OverrideNames:
423 field.name = OverrideNames[field.name]
427 def make_struct_h(self, struct):
429 if struct.doc: self.write_h(
" //", struct.doc)
434 self.write_h(
" struct %s %s\n {""" % (name, base)) 435 for field in struct.fields: 436 #if field.sourcetype: 439 if field.get_ctype() == "OpcUa::" + struct.name: 440 #we have a problem selv referensing struct 441 self.write_h(" std::shared_ptr<{}> {};".format(field.get_ctype(), field.name)) 443 self.write_h(" " , field.get_ctype(), field.name + ";") 444 if struct.needconstructor: 445 self.write_h("\n ", struct.name + "();") 449 def make_raw_size(self, struct): 451 self.write_size(" template<>") 452 self.write_size(" std::size_t RawSize<{}>(const {}& data)".format(struct.name, struct.name)) 453 self.write_size(" {") 455 if type(struct) == gm.Enum: 456 self.write_size(" return sizeof({});".format(struct.get_ctype())) 458 self.write_size(" size_t size = 0;") 459 for field in struct.fields: 461 if field.switchfield: 462 if field.switchvalue: 463 switch = "if ((data.{}) & (1<<({}))) ".format(field.switchfield, field.switchvalue) 465 container = struct.bits[field.switchfield].container 466 idx = struct.bits[field.switchfield].idx 467 switch = "if ((data.{}) & (1<<({}))) ".format(container, idx) 469 if field.get_ctype() == struct.name: 472 self.write_size(" {}size += RawSizeContainer({}data.{});".format(switch, prefix, field.name)) 474 self.write_size(" {}size += RawSize({}data.{});".format(switch, prefix, field.name)) 475 self.write_size(" return size;") 476 self.write_size(" }") 479 def make_serialize(self, struct): 481 self.write_ser(" template<>") 482 self.write_ser(" void DataSerializer::Serialize<{}>(const {}& data)".format(struct.name, struct.name)) 484 if type(struct) == gm.Enum: 485 self.write_ser(" *this << static_cast<{}>(data);".format(struct.get_ctype())) 487 for idx, field in enumerate(struct.fields): 488 if field.name == "Body" and idx != (len(struct.fields) - 1): 489 self.write_ser(" int32_t bodylength = RawSize(data) - RawSize(data.Encoding);") 490 self.write_ser(" if ((data.Encoding) & (1<<(0))) bodylength -= RawSize(data.TypeId);") 491 self.write_ser(" *this << bodylength;") 495 if field.switchfield: 496 if field.switchvalue: 497 switch = "if ((data.{}) & (1<<({}))) ".format(field.switchfield, field.switchvalue) 499 container = struct.bits[field.switchfield].container 500 idx = struct.bits[field.switchfield].idx 501 switch = "if ((data.{}) & (1<<({}))) ".format(container, idx) 503 if field.get_ctype() == struct.name: 506 self.write_ser(" {}SerializeContainer(*this, {}data.{});".format(switch, prefix, field.name)) 508 self.write_ser(" {}*this << {}data.{};".format(switch, prefix, field.name)) 512 def make_deserialize(self, struct): 514 self.write_deser(" template<>") 515 self.write_deser(" void DataDeserializer::Deserialize<{}>({}& data)".format(struct.name, struct.name)) 516 self.write_deser(" {") 517 if type(struct) == gm.Enum: 518 self.write_deser(" {} tmp;".format(struct.get_ctype())) 519 self.write_deser(" *this >> tmp;") 520 #self.write_deser(" data = static_cast<{}>(tmp);".format(struct.get_ctype())) 521 self.write_deser(" data = static_cast<{}>(tmp);".format(struct.name)) 523 for idx, field in enumerate(struct.fields): 524 if field.name == "Body" and idx != (len(struct.fields) - 1): 525 self.write_deser(" int32_t tmp; //Not used") 526 self.write_deser(" *this >> tmp;") 529 if field.switchfield: 530 if field.switchvalue: 531 switch = "if ((data.{}) & (1>>({}))) ".format(field.switchfield, field.switchvalue) 533 container = struct.bits[field.switchfield].container 534 idx = struct.bits[field.switchfield].idx 535 switch = "if ((data.{}) & (1>>({}))) ".format(container, idx) 537 self.write_deser(" {}DeserializeContainer(*this, data.{});".format(switch, field.name)) 539 self.write_deser(" {}*this >> data.{};".format(switch, field.name)) 540 self.write_deser(" }") 543 def make_request_constructors(self, struct): 544 if not struct.needconstructor: 547 self.write_const(" ", struct.name + "::" + struct.name + "()") 548 #self.write_const(" : TypeId(ObjectId::" + struct.name +"_Encoding_DefaultBinary)") 549 self.write_const(" : TypeId(FourByteNodeId((uint16_t)ObjectId::" + struct.name +"_Encoding_DefaultBinary))") 550 self.write_const(" {") 551 self.write_const(" }") 553 def make_struct_ser(self, struct): 554 self.make_raw_size(struct) 555 self.make_serialize(struct) 556 self.make_deserialize(struct) 558 def make_enum_h(self, enum): 559 self.write_enum("\n") 560 if enum.doc: self.write_enum(" //", enum.doc) 561 self.write_enum(" enum class %s : %s\n {" % (enum.name, self.to_enum_type(enum.uatype))) 562 for val in enum.values: 563 self.write_enum(" ", val.name, "=", val.value + ",") 564 self.write_enum(" };") 565 #if enum.name.endswith("Mask"): 566 self.write_enum(""" inline {name} operator|({name} a, {name} b) {{ return static_cast<{name}>(static_cast<{type}>(a) | static_cast<{type}>(b)); }}
""".format(name=enum.name, type=self.to_enum_type(enum.uatype))) 567 self.write_enum(""" inline {name} operator&({name} a, {name} b) {{ return static_cast<{name}>(static_cast<{type}>(a) & static_cast<{type}>(b)); }}
""".format(name=enum.name, type=self.to_enum_type(enum.uatype))) 570 def to_enum_type(self, val): 573 return "{}_t".format(val.lower()) 575 def write_h(self, *args): 576 self.h_file.write(" ".join(args) + "\n") 578 def write_enum(self, *args): 579 self.enum_file.write(" ".join(args) + "\n") 581 def write_ser(self, *args): 582 self.serialize_file.write(" ".join(args) + "\n") 584 def write_size(self, *args): 585 self.rawsize_file.write(" ".join(args) + "\n") 587 def write_deser(self, *args): 588 self.deserialize_file.write(" ".join(args) + "\n") 590 def write_const(self, *args): 591 self.constructors_file.write(" ".join(args) + "\n") 593 def make_header_h(self, ): 594 self.write_h('''// DO NOT EDIT THIS FILE! 595 // It is automatically generated from opcfoundation.org schemas. 598 /// @brief Opc Ua Binary. 599 /// @license GNU LGPL 601 /// Distributed under the GNU LGPL License 602 /// (See accompanying file LICENSE or copy at 603 /// http://www.gnu.org/licenses/lgpl.html) 608 #include <opc/ua/protocol/enums.h> 609 #include <opc/ua/protocol/variable_access_level.h> 610 #include <opc/ua/protocol/attribute_ids.h> 611 #include <opc/ua/protocol/nodeid.h> 612 #include <opc/ua/protocol/types.h> 613 #include <opc/ua/protocol/types_manual.h> 614 #include <opc/ua/protocol/variant.h> 615 #include <opc/ua/protocol/data_value.h> 620 def make_footer_h(self): 625 def make_header_enum(self, ): 626 self.write_enum('''// DO NOT EDIT THIS FILE! 627 // It is automatically generated from opcfoundation.org schemas. 630 /// @brief Opc Ua Binary. 631 /// @license GNU LGPL 633 /// Distributed under the GNU LGPL License 634 /// (See accompanying file LICENSE or copy at 635 /// http://www.gnu.org/licenses/lgpl.html) 644 #include <opc/ua/protocol/status_codes.h> 648 struct DiagnosticInfo; 651 def make_footer_enum(self): 656 def make_header_rawsize(self, ): 657 self.write_size('''// DO NOT EDIT THIS FILE! 658 // It is automatically generated from opcfoundation.org schemas. 661 /// @author Olivier Roulet-Dubonnet 662 /// @email olivier@sintef.no 663 /// @brief Opc Ua Binary. 664 /// @license GNU LGPL 666 /// Distributed under the GNU LGPL License 667 /// (See accompanying file LICENSE or copy at 668 /// http://www.gnu.org/licenses/lgpl.html) 671 #include "binary_serialization.h" 672 #include <opc/ua/protocol/protocol.h> 674 #include <opc/ua/protocol/binary/stream.h> 681 def make_footer_rawsize(self): 690 def make_header_serialize(self, ): 691 self.write_ser('''// DO NOT EDIT THIS FILE! 692 // It is automatically generated from opcfoundation.org schemas. 695 /// @author Olivier Roulet-Dubonnet 696 /// @email olivier@sintef.no 697 /// @brief Opc Ua Binary. 698 /// @license GNU LGPL 700 /// Distributed under the GNU LGPL License 701 /// (See accompanying file LICENSE or copy at 702 /// http://www.gnu.org/licenses/lgpl.html) 705 #include "binary_serialization.h" 706 #include <opc/ua/protocol/protocol.h> 708 #include <opc/ua/protocol/binary/stream.h> 715 def make_footer_serialize(self): 722 def make_header_deserialize(self, ): 723 self.write_deser('''// DO NOT EDIT THIS FILE! 724 // It is automatically generated from opcfoundation.org schemas. 727 /// @author Olivier Roulet-Dubonnet 728 /// @email olivier@sintef.no 729 /// @brief Opc Ua Binary. 730 /// @license GNU LGPL 732 /// Distributed under the GNU LGPL License 733 /// (See accompanying file LICENSE or copy at 734 /// http://www.gnu.org/licenses/lgpl.html) 737 #include "binary_serialization.h" 738 #include <opc/ua/protocol/protocol.h> 740 #include <opc/ua/protocol/binary/stream.h> 747 def make_footer_deserialize(self): 755 def make_header_constructors(self, ): 756 self.write_const('''// DO NOT EDIT THIS FILE! 757 // It is automatically generated from opcfoundation.org schemas. 760 /// @author Olivier Roulet-Dubonnet 761 /// @email olivier@sintef.no 762 /// @brief Opc Ua Binary. 763 /// @license GNU LGPL 765 /// Distributed under the GNU LGPL License 766 /// (See accompanying file LICENSE or copy at 767 /// http://www.gnu.org/licenses/lgpl.html) 770 #include <opc/ua/protocol/protocol_auto.h> 771 #include <opc/ua/protocol/object_ids.h> 776 def make_footer_constructors(self): 784 if __name__ == "__main__": 785 xmlpath = "Opc.Ua.Types.bsd" 786 hpath = "../include/opc/ua/protocol/protocol_auto.h" 787 enumpath = "../include/opc/ua/protocol/enums.h" 788 serializerpath = "../src/protocol/serialize_auto.cpp" 789 rawsizepath = "../src/protocol/rawsize_auto.cpp" 790 deserializerpath = "../src/protocol/deserialize_auto.cpp" 791 constructorspath = "../src/protocol/constructors_auto.cpp" 793 p = gm.Parser(xmlpath) 795 gm.add_basetype_members(model) 796 gm.add_encoding_field(model) 797 gm.remove_duplicates(model) 798 gm.remove_vector_length(model) 799 gm.split_requests(model, NoSplitStruct) 803 #Changes specific to our C++ implementation 804 #reorder_extobjects(model) 805 #add_basetype_members(model) 806 #add_encoding_field(model) 807 #remove_vector_length(model) 808 #remove_body_length(model) 809 #remove_duplicates(model) 810 #split_requests(model) 811 reorder_structs(model) 812 override_types(model) 814 f = open("struct_list.txt", "w") 815 f.write("enabled_structs = [\\") 816 for name in model.struct_list: 817 f.write("\n #'" + name + "',") 821 c = CodeGenerator(model, hpath, enumpath, rawsizepath, serializerpath, deserializerpath, constructorspath) FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args)
std::string format(CStringRef format_str, ArgList args)