diff --git a/etsi_its_conversion/etsi_its_denm_conversion/include/etsi_its_denm_conversion/convertVehicleIdentification.h b/etsi_its_conversion/etsi_its_denm_conversion/include/etsi_its_denm_conversion/convertVehicleIdentification.h index a5ec23bd..9a75fd9b 100644 --- a/etsi_its_conversion/etsi_its_denm_conversion/include/etsi_its_denm_conversion/convertVehicleIdentification.h +++ b/etsi_its_conversion/etsi_its_denm_conversion/include/etsi_its_denm_conversion/convertVehicleIdentification.h @@ -42,25 +42,25 @@ namespace etsi_its_denm_conversion { void toRos_VehicleIdentification(const denm_VehicleIdentification_t& in, denm_msgs::VehicleIdentification& out) { if (in.wMInumber) { - toRos_WMInumber(*in.wMInumber, out.wm_inumber); - out.wm_inumber_is_present = true; + toRos_WMInumber(*in.wMInumber, out.w_m_inumber); + out.w_m_inumber_is_present = true; } if (in.vDS) { - toRos_VDS(*in.vDS, out.vds); - out.vds_is_present = true; + toRos_VDS(*in.vDS, out.v_ds); + out.v_ds_is_present = true; } } void toStruct_VehicleIdentification(const denm_msgs::VehicleIdentification& in, denm_VehicleIdentification_t& out) { memset(&out, 0, sizeof(denm_VehicleIdentification_t)); - if (in.wm_inumber_is_present) { + if (in.w_m_inumber_is_present) { out.wMInumber = (denm_WMInumber_t*) calloc(1, sizeof(denm_WMInumber_t)); - toStruct_WMInumber(in.wm_inumber, *out.wMInumber); + toStruct_WMInumber(in.w_m_inumber, *out.wMInumber); } - if (in.vds_is_present) { + if (in.v_ds_is_present) { out.vDS = (denm_VDS_t*) calloc(1, sizeof(denm_VDS_t)); - toStruct_VDS(in.vds, *out.vDS); + toStruct_VDS(in.v_ds, *out.vDS); } } diff --git a/etsi_its_conversion/etsi_its_mapem_ts_conversion/include/etsi_its_mapem_ts_conversion/convertNodeOffsetPointXY.h b/etsi_its_conversion/etsi_its_mapem_ts_conversion/include/etsi_its_mapem_ts_conversion/convertNodeOffsetPointXY.h index f61994f5..7a9aa904 100644 --- a/etsi_its_conversion/etsi_its_mapem_ts_conversion/include/etsi_its_mapem_ts_conversion/convertNodeOffsetPointXY.h +++ b/etsi_its_conversion/etsi_its_mapem_ts_conversion/include/etsi_its_mapem_ts_conversion/convertNodeOffsetPointXY.h @@ -49,27 +49,27 @@ void toRos_NodeOffsetPointXY(const mapem_ts_NodeOffsetPointXY_t& in, mapem_ts_ms switch (in.present) { case mapem_ts_NodeOffsetPointXY_PR_node_XY1: toRos_NodeXY20b(in.choice.node_XY1, out.node_xy1); - out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y1; + out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY1; break; case mapem_ts_NodeOffsetPointXY_PR_node_XY2: toRos_NodeXY22b(in.choice.node_XY2, out.node_xy2); - out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y2; + out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY2; break; case mapem_ts_NodeOffsetPointXY_PR_node_XY3: toRos_NodeXY24b(in.choice.node_XY3, out.node_xy3); - out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y3; + out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY3; break; case mapem_ts_NodeOffsetPointXY_PR_node_XY4: toRos_NodeXY26b(in.choice.node_XY4, out.node_xy4); - out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y4; + out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY4; break; case mapem_ts_NodeOffsetPointXY_PR_node_XY5: toRos_NodeXY28b(in.choice.node_XY5, out.node_xy5); - out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y5; + out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY5; break; case mapem_ts_NodeOffsetPointXY_PR_node_XY6: toRos_NodeXY32b(in.choice.node_XY6, out.node_xy6); - out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y6; + out.choice = mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY6; break; case mapem_ts_NodeOffsetPointXY_PR_node_LatLon: toRos_NodeLLmD64b(in.choice.node_LatLon, out.node_lat_lon); @@ -83,27 +83,27 @@ void toStruct_NodeOffsetPointXY(const mapem_ts_msgs::NodeOffsetPointXY& in, mape memset(&out, 0, sizeof(mapem_ts_NodeOffsetPointXY_t)); switch (in.choice) { - case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y1: + case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY1: toStruct_NodeXY20b(in.node_xy1, out.choice.node_XY1); out.present = mapem_ts_NodeOffsetPointXY_PR::mapem_ts_NodeOffsetPointXY_PR_node_XY1; break; - case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y2: + case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY2: toStruct_NodeXY22b(in.node_xy2, out.choice.node_XY2); out.present = mapem_ts_NodeOffsetPointXY_PR::mapem_ts_NodeOffsetPointXY_PR_node_XY2; break; - case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y3: + case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY3: toStruct_NodeXY24b(in.node_xy3, out.choice.node_XY3); out.present = mapem_ts_NodeOffsetPointXY_PR::mapem_ts_NodeOffsetPointXY_PR_node_XY3; break; - case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y4: + case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY4: toStruct_NodeXY26b(in.node_xy4, out.choice.node_XY4); out.present = mapem_ts_NodeOffsetPointXY_PR::mapem_ts_NodeOffsetPointXY_PR_node_XY4; break; - case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y5: + case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY5: toStruct_NodeXY28b(in.node_xy5, out.choice.node_XY5); out.present = mapem_ts_NodeOffsetPointXY_PR::mapem_ts_NodeOffsetPointXY_PR_node_XY5; break; - case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_X_Y6: + case mapem_ts_msgs::NodeOffsetPointXY::CHOICE_NODE_XY6: toStruct_NodeXY32b(in.node_xy6, out.choice.node_XY6); out.present = mapem_ts_NodeOffsetPointXY_PR::mapem_ts_NodeOffsetPointXY_PR_node_XY6; break; diff --git a/etsi_its_msgs/etsi_its_denm_msgs/msg/PositioningSolutionType.msg b/etsi_its_msgs/etsi_its_denm_msgs/msg/PositioningSolutionType.msg index e901ab59..c2c52197 100644 --- a/etsi_its_msgs/etsi_its_denm_msgs/msg/PositioningSolutionType.msg +++ b/etsi_its_msgs/etsi_its_denm_msgs/msg/PositioningSolutionType.msg @@ -32,7 +32,7 @@ uint8 value uint8 NO_POSITIONING_SOLUTION = 0 uint8 S_GNSS = 1 uint8 D_GNSS = 2 -uint8 S_GNSS_PLUS_D_R = 3 -uint8 D_GNSS_PLUS_D_R = 4 +uint8 S_GNS_SPLUS_DR = 3 +uint8 D_GNS_SPLUS_DR = 4 uint8 D_R = 5 diff --git a/etsi_its_msgs/etsi_its_denm_msgs/msg/VehicleIdentification.msg b/etsi_its_msgs/etsi_its_denm_msgs/msg/VehicleIdentification.msg index f53e521e..1592da2b 100644 --- a/etsi_its_msgs/etsi_its_denm_msgs/msg/VehicleIdentification.msg +++ b/etsi_its_msgs/etsi_its_denm_msgs/msg/VehicleIdentification.msg @@ -32,9 +32,9 @@ # } # ------------------------------------------------------------------------------ -WMInumber wm_inumber -bool wm_inumber_is_present +WMInumber w_m_inumber +bool w_m_inumber_is_present -VDS vds -bool vds_is_present +VDS v_ds +bool v_ds_is_present diff --git a/etsi_its_msgs/etsi_its_mapem_ts_msgs/msg/NodeOffsetPointXY.msg b/etsi_its_msgs/etsi_its_mapem_ts_msgs/msg/NodeOffsetPointXY.msg index 1f93aa42..856789bf 100644 --- a/etsi_its_msgs/etsi_its_mapem_ts_msgs/msg/NodeOffsetPointXY.msg +++ b/etsi_its_msgs/etsi_its_mapem_ts_msgs/msg/NodeOffsetPointXY.msg @@ -39,22 +39,22 @@ uint8 choice NodeXY20b node_xy1 -uint8 CHOICE_NODE_X_Y1 = 0 +uint8 CHOICE_NODE_XY1 = 0 NodeXY22b node_xy2 -uint8 CHOICE_NODE_X_Y2 = 1 +uint8 CHOICE_NODE_XY2 = 1 NodeXY24b node_xy3 -uint8 CHOICE_NODE_X_Y3 = 2 +uint8 CHOICE_NODE_XY3 = 2 NodeXY26b node_xy4 -uint8 CHOICE_NODE_X_Y4 = 3 +uint8 CHOICE_NODE_XY4 = 3 NodeXY28b node_xy5 -uint8 CHOICE_NODE_X_Y5 = 4 +uint8 CHOICE_NODE_XY5 = 4 NodeXY32b node_xy6 -uint8 CHOICE_NODE_X_Y6 = 5 +uint8 CHOICE_NODE_XY6 = 5 NodeLLmD64b node_lat_lon uint8 CHOICE_NODE_LAT_LON = 6 diff --git a/etsi_its_msgs/etsi_its_spatem_ts_msgs/msg/IntersectionStatusObject.msg b/etsi_its_msgs/etsi_its_spatem_ts_msgs/msg/IntersectionStatusObject.msg index 5ec690c7..7c19283a 100644 --- a/etsi_its_msgs/etsi_its_spatem_ts_msgs/msg/IntersectionStatusObject.msg +++ b/etsi_its_msgs/etsi_its_spatem_ts_msgs/msg/IntersectionStatusObject.msg @@ -56,8 +56,8 @@ uint8 BIT_INDEX_TRAFFIC_DEPENDENT_OPERATION = 6 uint8 BIT_INDEX_STANDBY_OPERATION = 7 uint8 BIT_INDEX_FAILURE_MODE = 8 uint8 BIT_INDEX_OFF = 9 -uint8 BIT_INDEX_RECENT_M_A_PMESSAGE_UPDATE = 10 -uint8 BIT_INDEX_RECENT_CHANGE_IN_M_A_PASSIGNED_LANES_IDS_USED = 11 -uint8 BIT_INDEX_NO_VALID_M_A_PIS_AVAILABLE_AT_THIS_TIME = 12 -uint8 BIT_INDEX_NO_VALID_SPATIS_AVAILABLE_AT_THIS_TIME = 13 +uint8 BIT_INDEX_RECENT_MA_PMESSAGE_UPDATE = 10 +uint8 BIT_INDEX_RECENT_CHANGE_IN_MA_PASSIGNED_LANES_I_DS_USED = 11 +uint8 BIT_INDEX_NO_VALID_MA_PIS_AVAILABLE_AT_THIS_TIME = 12 +uint8 BIT_INDEX_NO_VALID_SPA_TIS_AVAILABLE_AT_THIS_TIME = 13 diff --git a/etsi_its_msgs/etsi_its_vam_ts_msgs/msg/TrajectoryInterceptionConfidence.msg b/etsi_its_msgs/etsi_its_vam_ts_msgs/msg/TrajectoryInterceptionConfidence.msg index 9a78ff6a..aa2d0139 100644 --- a/etsi_its_msgs/etsi_its_vam_ts_msgs/msg/TrajectoryInterceptionConfidence.msg +++ b/etsi_its_msgs/etsi_its_vam_ts_msgs/msg/TrajectoryInterceptionConfidence.msg @@ -48,8 +48,8 @@ uint8 value uint8 MIN = 0 uint8 MAX = 3 -uint8 LESSTHAN50PERCENT = 0 -uint8 BETWEEN50AND70_PERCENT = 1 -uint8 BETWEEN70AND90_PERCENT = 2 +uint8 LESSTHAN50_PERCENT = 0 +uint8 BETWEEN50_AND70_PERCENT = 1 +uint8 BETWEEN70_AND90_PERCENT = 2 uint8 ABOVE90_PERCENT = 3 diff --git a/utils/codegen/codegen-py/asn1CodeGenerationUtils.py b/utils/codegen/codegen-py/asn1CodeGenerationUtils.py index 93099d13..9b5bea1d 100644 --- a/utils/codegen/codegen-py/asn1CodeGenerationUtils.py +++ b/utils/codegen/codegen-py/asn1CodeGenerationUtils.py @@ -44,135 +44,107 @@ } -def camel2SNAKE(s: str) -> str: - """Converts a camelCase string to SNAKE_CASE. - - Args: - s (str): camelCaseString - - Returns: - str: SNAKE_CASE_STRING - """ - - # exampleString-WithNumber123 -> example_string-_With_Number123 - ss = re.sub("([A-Z])", r"_\1", s) - - # example_string-_With_Number123 -> EXAMPLE_STRING_WITH_NUMBER123 - ss = ss.upper().lstrip("_").replace("-", "_").replace("__", "_") - - # EXAMPLE_STRING_WITH_NUMBER123 -> EXAMPLE_STRING_WITH_NUMBER_123 - # ss = re.sub("([A-Z])([0-9])", r"\1_\2", ss) - - # special cases - ss = ss.replace("C_A_M", "CAM") - ss = ss.replace("D_E_N_M", "DENM") - ss = ss.replace("S_P_A_T_E_M", "SPATEM") - ss = ss.replace("S_P_A_T", "SPAT") - ss = ss.replace("D_S_R_C", "DSRC") - ss = ss.replace("R_S_U", "RSU") - ss = ss.replace("W_M_I", "WMI") - ss = ss.replace("V_DS", "VDS") - ss = ss.replace("_I_D", "_ID") - ss = ss.replace("_U_T_C", "_UTC") - ss = ss.replace("G_N_S_S", "GNSS") - ss = ss.replace("GNSSPLUS", "GNSS_PLUS") - - return ss +def validRosType(s: str) -> str: + """Converts a string to make it a valid ROS message type. -def camel2snake(s: str) -> str: - """Converts a camelCase string to snake_case. + Regex: ^[A-Z][A-Za-z0-9]*$ Args: - s (str): camelCaseString + s (str): A-Message-Type Returns: - str: snake_case_string + str: A_Message_Type """ - # exampleString-WithNumber123 -> example_string-_With_Number123 - ss = re.sub("([A-Z])", r"_\1", s) - - # example_string-_With_Number123 -> example_string_with_number123 - ss = ss.lower().lstrip("_").replace("-", "_").replace("__", "_") - - # example_string_with_number123 -> example_string_with_number_123 - # ss = re.sub("([a-z])([0-9])", r"\1_\2", ss) - - # special cases - ss = ss.replace("c_a_m", "cam") - ss = ss.replace("d_e_n_m", "denm") - ss = ss.replace("s_p_a_t_e_m", "spatem") - ss = ss.replace("s_p_a_t", "spat") - ss = ss.replace("m_a_p_e_m", "mapem") - ss = ss.replace("m_a_p", "map") - ss = ss.replace("v_a_m", "vam") - ss = ss.replace("d_s_r_c", "dsrc") - ss = ss.replace("r_s_u", "rsu") - ss = ss.replace("w_m_i", "wmi") - ss = ss.replace("v_d_s", "vds") - ss = ss.replace("_i_d", "_id") - ss = ss.replace("_u_t_c", "_utc") - ss = ss.replace("wmin", "wm_in") - ss = ss.replace("_3_d", "3_d") - ss = ss.replace("_b_1", "_b1") - ss = ss.replace("_x_y_2", "_xy2") - ss = ss.replace("_x_y_3", "_xy3") - ss = ss.replace("_x_y", "_xy") - ss = ss.replace("_l_lm_d_6", "_l_lm_d6") + ss = s - return ss + # keep built-in types as they are + if ss.rstrip("[]") in ["bool", "byte", "char", "float32", "float64", "int8", "uint8", "int16", "uint16", "int32", "uint32", "int64", "uint64", "string", "wstring"]: + return ss -def validRosType(s: str) -> str: - """Converts a string to make it a valid ROS message type. + # remove - and _ + ss = ss.replace("-", "").replace("_", "") - Args: - s (str): Not-A-Message-Type + # make sure first character is a letter + if not ss[0].isalpha(): + ss = "A" + ss - Returns: - str: A_Message_Type - """ + # capitalize first letter + ss = ss[0].upper() + ss[1:] - return s.replace("-", "") + return ss def validRosField(s: str, is_const: bool = False) -> str: """Converts a string to make it a valid ROS message field name. + Regex for field: ^(?!.*__)(?!.*_$)[a-z][a-z0-9_]*$ + Regex for constant: ^[A-Z]([A-Z0-9_]?[A-Z0-9]+)*$ + Args: - s (str): Not-A-Ros-Message-Field + s (str): A-Ros-Message-Field is_const (bool): whether the field is a constant Returns: - str: a_ros_message_field or A_ROS_MESSAGE_CONSTANT + str: a_ros_message_field or A_ROS_MESSAGE_FIELD """ - ss = s.upper() if is_const else s.lower() + ss = s + + # add _ before upper-case letters following lower-case letters or numbers + ss = re.sub("(?<=[a-z0-9])([A-Z])", r"_\1", ss) + + # add _ before upper-case letters before lower-case letters + ss = re.sub("([A-Z])(?=[a-z])", r"_\1", ss) + + # remove leading _, replace - with _, remove double _ + ss = ss.lstrip("_").replace("-", "_").replace("__", "_") + + # to upper, if const + ss = ss.upper() if is_const else ss.lower() # avoid C/C++ keywords - if ss == "long": - ss = "lon" if ss == "class": ss = "cls" + if ss == "long": + ss = "lon" return ss -def validCField(s: str, is_const: bool = False) -> str: - """Converts a string to make it a valid C message field name. +def validRosTypeHeader(s: str) -> str: + """Converts a string to make it a valid ROS message header file name. Args: - s (str): e.g., "class" + s (str): A-Message-Type + + Returns: + str: a_message_type + """ + + return validRosField(validRosType(s)) + + +def validCFieldAsGenByAsn1c(s: str) -> str: + """Converts a string to make it a valid C message field name as generated by asn1c. + + Args: + s (str): e.g., "cla-ss" Returns: str: e.g., "Class" """ + ss = s + + # replace - with _ + ss = ss.replace("-", "_") + # avoid C/C++ keywords - ss = s.replace("-", "_") - if ss == "long": - ss = "Long" if ss == "class": ss = "Class" + if ss == "long": + ss = "Long" return ss @@ -190,19 +162,6 @@ def noSpace(s: str) -> str: return s.replace(" ", "_") -def noDash(s: str) -> str: - """Replaces any dashes in a string with nothing. - - Args: - s (str): my string - - Returns: - str: my_string - """ - - return s.replace("-", "") - - def simplestRosIntegerType(min_value: int, max_value: int) -> str: """Returns the simplest/smallest ROS integer type covering the specified range. @@ -367,10 +326,10 @@ def checkTypeMembersInAsn1(asn1_types: Dict[str, Dict]): known_types += list(ASN1_PRIMITIVES_2_ROS.keys()) # loop all types - for t_name, type in asn1_types.items(): + for asn1_type_name, asn1_type_info in asn1_types.items(): # loop all members in type - for member in type.get("members", []): + for member in asn1_type_info.get("members", []): if member is None: continue @@ -383,176 +342,172 @@ def checkTypeMembersInAsn1(asn1_types: Dict[str, Dict]): if ".&" in member["type"]: warnings.warn( f"Type '{member['type']}' of member '{member['name']}' " - f"in '{t_name}' seems to relate to a 'CLASS' type, not " + f"in '{asn1_type_name}' seems to relate to a 'CLASS' type, not " f"yet supported") else: raise TypeError( f"Type '{member['type']}' of member '{member['name']}' " - f"in '{t_name}' is undefined") + f"in '{asn1_type_name}' is undefined") -def asn1TypeToJinjaContext(t_name: str, asn1: Dict, asn1_types: Dict[str, Dict], asn1_values: Dict[str, Dict]) -> Dict: +def asn1TypeToJinjaContext(asn1_type_name: str, asn1_type_info: Dict, asn1_types: Dict[str, Dict], asn1_values: Dict[str, Dict]) -> Dict: """Builds a jinja context containing all type information required to fill the templates / code generation. Args: - t_name (str): type name - asn1 (Dict): type information + asn1_type_name (str): type name + asn1_type_info (Dict): type information asn1_types (Dict[str, Dict]): type information of all types by type asn1_values (Dict[str, Dict]): value information of all values by name Returns: Dict: jinja context """ - - if "components-of" in asn1: # TODO - warnings.warn(f"Handling of 'components-of' in '{t_name}' not yet supported.") + + if "components-of" in asn1_type_info: + warnings.warn(f"Handling of 'components-of' in '{asn1_type_name}' not yet supported.") return { # generate in a way such that compilation will not succeed - "asn1_definition": None, - "comments": [], "etsi_type": None, - "members": [{"t_name": t_name, "type": "TODO: components-of", "name": "is not yet supported", "name_cc": "is not yet supported"}], - "t_name": t_name, - "t_name_camel": noDash(t_name), - "t_name_snake": camel2snake(t_name), - "type": "components-of", - "asn1_type": "components-of", + "asn1_type_type": "components-of", + "asn1_type_name": asn1_type_name, + "ros_msg_type": validRosType(asn1_type_name), + "ros2_msg_type_file_name": validRosTypeHeader(asn1_type_name), "is_primitive": False, + "members": [{"asn1_type_name": asn1_type_name, "ros_msg_type": "TODO: components-of", "ros_field_name": "is not yet supported", "c_field_name": "is not yet supported"}], + "asn1_definition": None, + "comments": [], } - - type = asn1["type"] + + asn1_type_type = asn1_type_info["type"] context = { + "etsi_type": None, # cam + "asn1_type_type": noSpace(asn1_type_type), # SEQUENCE + "asn1_type_name": asn1_type_name, # CamParameters + "ros_msg_type": validRosType(asn1_type_name), # CamParameters + "ros2_msg_type_file_name": validRosTypeHeader(asn1_type_name), # cam_parameters + "is_primitive": False, + "members": [], "asn1_definition": None, "comments": [], - "etsi_type": None, - "members": [], - "t_name": t_name, - "t_name_camel": noDash(t_name), - "t_name_snake": camel2snake(t_name), - "type": noSpace(type), - "asn1_type": type, - "is_primitive": False, } # extra information / asn1 fields that are not processed as comments - for k, v in asn1.items(): + for k, v in asn1_type_info.items(): if k not in ("type", "element", "members", "name", "named-bits", "named-numbers", "optional", "restricted-to", "size", "values", "default"): context["comments"].append(f"{k}: {v}") # primitives - if type in ASN1_PRIMITIVES_2_ROS: + if asn1_type_type in ASN1_PRIMITIVES_2_ROS: # resolve ROS msg type - ros_type = ASN1_PRIMITIVES_2_ROS[type] - name = asn1["name"] if "name" in asn1 else "value" + ros_type = ASN1_PRIMITIVES_2_ROS[asn1_type_type] + name = asn1_type_info["name"] if "name" in asn1_type_info else "value" # choose simplest possible integer type - if "restricted-to" in asn1 and type == "INTEGER": - min_value = asn1["restricted-to"][0][0] - max_value = asn1["restricted-to"][0][1] + if "restricted-to" in asn1_type_info and asn1_type_type == "INTEGER": + min_value = asn1_type_info["restricted-to"][0][0] + max_value = asn1_type_info["restricted-to"][0][1] ros_type = simplestRosIntegerType(min_value, max_value) # parse member to jinja context member_context = { - "type": ros_type, - "asn1_type": type, - "t_name": type, - "name": validRosField(camel2snake(name)), - "name_cc": validCField(name), + "asn1_type_name": asn1_type_type, + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(name), + "c_field_name": validCFieldAsGenByAsn1c(name), "constants": [], "is_primitive": True, "has_bits_unused": False, } # add bits_unused field for BIT STRINGs - if type == "BIT STRING": + if asn1_type_type == "BIT STRING": member_context["has_bits_unused"] = True # add constants for limits - if "restricted-to" in asn1: - min_value = asn1["restricted-to"][0][0] - max_value = asn1["restricted-to"][0][1] + if "restricted-to" in asn1_type_info: + min_value = asn1_type_info["restricted-to"][0][0] + max_value = asn1_type_info["restricted-to"][0][1] min_constant_name = "MIN" max_constant_name = "MAX" - if "name" in asn1: - min_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{min_constant_name}", is_const=True) - max_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{max_constant_name}", is_const=True) + if "name" in asn1_type_info: + min_constant_name = validRosField(f"{asn1_type_info['name']}_{min_constant_name}", is_const=True) + max_constant_name = validRosField(f"{asn1_type_info['name']}_{max_constant_name}", is_const=True) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(min_constant_name, is_const=True), - "value": min_value + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(min_constant_name, is_const=True), + "ros_value": min_value }) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(max_constant_name, is_const=True), - "value": max_value + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(max_constant_name, is_const=True), + "ros_value": max_value }) # add constants for size limits - if "size" in asn1: - if isinstance(asn1["size"][0], tuple): - min_size = asn1["size"][0][0] - max_size = asn1["size"][0][1] + if "size" in asn1_type_info: + if isinstance(asn1_type_info["size"][0], tuple): + min_size = asn1_type_info["size"][0][0] + max_size = asn1_type_info["size"][0][1] ros_type = simplestRosIntegerType(min_size, max_size) - min_size_constant_name = "MIN_SIZE" if type != "BIT STRING" else "MIN_SIZE_BITS" - max_size_constant_name = "MAX_SIZE" if type != "BIT STRING" else "MAX_SIZE_BITS" - if "name" in asn1: - min_size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{min_size_constant_name}", is_const=True) - max_size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{max_size_constant_name}", is_const=True) + min_size_constant_name = "MIN_SIZE" if asn1_type_type != "BIT STRING" else "MIN_SIZE_BITS" + max_size_constant_name = "MAX_SIZE" if asn1_type_type != "BIT STRING" else "MAX_SIZE_BITS" + if "name" in asn1_type_info: + min_size_constant_name = validRosField(f"{asn1_type_info['name']}_{min_size_constant_name}", is_const=True) + max_size_constant_name = validRosField(f"{asn1_type_info['name']}_{max_size_constant_name}", is_const=True) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(min_size_constant_name, is_const=True), - "value": min_size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(min_size_constant_name, is_const=True), + "ros_value": min_size }) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(max_size_constant_name, is_const=True), - "value": max_size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(max_size_constant_name, is_const=True), + "ros_value": max_size }) else: - size = asn1["size"][0] + size = asn1_type_info["size"][0] ros_type = simplestRosIntegerType(size, size) - size_constant_name = "SIZE" if type != "BIT STRING" else "SIZE_BITS" - if "name" in asn1: - size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{size_constant_name}", is_const=True) + size_constant_name = "SIZE" if asn1_type_type != "BIT STRING" else "SIZE_BITS" + if "name" in asn1_type_info: + size_constant_name = validRosField(f"{asn1_type_info['name']}_{size_constant_name}", is_const=True) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(size_constant_name, is_const=True), - "value": size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(size_constant_name, is_const=True), + "ros_value": size }) # add constants for named numbers - if "named-numbers" in asn1: - for k, v in asn1["named-numbers"].items(): - constant_name = validRosField(camel2SNAKE(k)) - if "name" in asn1: - constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{constant_name}", is_const=True) + if "named-numbers" in asn1_type_info: + for k, v in asn1_type_info["named-numbers"].items(): + constant_name = validRosField(k, is_const=True) + if "name" in asn1_type_info: + constant_name = validRosField(f"{asn1_type_info['name']}_{constant_name}", is_const=True) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(constant_name, is_const=True), - "value": v + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(constant_name, is_const=True), + "ros_value": v }) # add index constants for named bits - if "named-bits" in asn1: - for k, v in asn1["named-bits"]: - constant_name = camel2SNAKE(k) + if "named-bits" in asn1_type_info: + for k, v in asn1_type_info["named-bits"]: member_context["constants"].append({ - "type": "uint8", - "name": validRosField(f"BIT_INDEX_{constant_name}", is_const=True), - "value": v + "ros_msg_type": "uint8", + "ros_field_name": validRosField(f"BIT_INDEX_{k}", is_const=True), + "ros_value": v }) context["members"].append(member_context) # nested types - elif type == "SEQUENCE": + elif asn1_type_type == "SEQUENCE": # recursively add all members - for member in asn1["members"]: + for member in asn1_type_info["members"]: if member is None: continue - member_context = asn1TypeToJinjaContext(t_name, member, asn1_types, asn1_values) + member_context = asn1TypeToJinjaContext(asn1_type_name, member, asn1_types, asn1_values) if member_context is None: continue if "optional" in member: @@ -570,197 +525,196 @@ def asn1TypeToJinjaContext(t_name: str, asn1: Dict, asn1_types: Dict[str, Dict], asn1_value["value"] = default_tuple[1] asn1_value["type"] = asn1_types[member["type"]]["type"] default_value = asn1_value["value"] - default_name = validRosField(f"{camel2SNAKE(member['name'])}_DEFAULT", is_const=True) + default_name = validRosField(f"{member['name']}_DEFAULT", is_const=True) if asn1_value["type"] == 'INTEGER' or asn1_value["type"] == 'ENUMERATED': default_type = simplestRosIntegerType(default_value, default_value) else: default_type = ASN1_PRIMITIVES_2_ROS[asn1_value["type"]] member_context["members"][0]["default"] = { - "type": default_type, - "name": default_name, - "value": default_value + "ros_msg_type": validRosType(default_type), + "ros_field_name": validRosField(default_name, is_const=True), + "ros_value": default_value } context["members"].extend(member_context["members"]) # type aliases with multiple options - elif type == "CHOICE": + elif asn1_type_type == "CHOICE": # add flag for indicating active option name = "choice" - if "name" in asn1: - name = f"{asn1['name']}_{name}" - name = validRosField(camel2snake(name)) + if "name" in asn1_type_info: + name = f"{asn1_type_info['name']}_{name}" + name = validRosField(name) context["members"].append({ - "type": "uint8", - "name": name, + "ros_msg_type": "uint8", + "ros_field_name": validRosField(name), "is_choice_var": True }) # recursively add members for all options, incl. constant for flag - for im, member in enumerate(asn1["members"]): + for im, member in enumerate(asn1_type_info["members"]): if member is None: continue - member_name = validRosField(f"CHOICE_{camel2SNAKE(member['name'])}", is_const=True) - if "name" in asn1: - member_name = validRosField(f"CHOICE_{camel2SNAKE(asn1['name'])}_{camel2SNAKE(member['name'])}", is_const=True) - member_context = asn1TypeToJinjaContext(t_name, member, asn1_types, asn1_values) + member_name = validRosField(f"CHOICE_{member['name']}", is_const=True) + if "name" in asn1_type_info: + member_name = validRosField(f"CHOICE_{asn1_type_info['name']}_{member['name']}", is_const=True) + member_context = asn1TypeToJinjaContext(asn1_type_name, member, asn1_types, asn1_values) if member_context is None: continue if len(member_context["members"]) > 0: - if "name" in asn1: - member_context["members"][0]["choice_name"] = validCField(asn1["name"]) - member_context["members"][0]["choice_option_name"] = validCField(member_context["members"][0]["name_cc"]) - member_context["members"][0]["name"] = validRosField(f"{camel2snake(asn1['name'])}_{camel2snake(member_context['members'][0]['name'])}") - member_context["members"][0]["name_cc"] = validCField(f"{asn1['name']}_{member_context['members'][0]['name_cc']}") + if "name" in asn1_type_info: + member_context["members"][0]["choice_name"] = validCFieldAsGenByAsn1c(asn1_type_info["name"]) + member_context["members"][0]["choice_option_name"] = validCFieldAsGenByAsn1c(member_context["members"][0]["c_field_name"]) + member_context["members"][0]["ros_field_name"] = validRosField(f"{asn1_type_info['name']}_{member_context['members'][0]['ros_field_name']}") + member_context["members"][0]["c_field_name"] = validCFieldAsGenByAsn1c(f"{asn1_type_info['name']}_{member_context['members'][0]['c_field_name']}") member_context["members"][0]["is_choice"] = True member_context["members"][0]["choice_var_name"] = name member_context["members"][0]["constants"] = member_context["members"][0].get("constants", []) for c_idx, constant in enumerate(member_context["members"][0]["constants"]): - member_context["members"][0]["constants"][c_idx]["name"] = validRosField(f"{member_context['members'][0]['name']}_{constant['name']}", is_const=True) + member_context["members"][0]["constants"][c_idx]["ros_field_name"] = validRosField(f"{member_context['members'][0]['ros_field_name']}_{constant['ros_field_name']}", is_const=True) member_context["members"][0]["constants"].append({ - "type": "uint8", - "name": member_name, - "value": im + "ros_msg_type": "uint8", + "ros_field_name": validRosField(member_name, is_const=True), + "ros_value": im }) context["members"].extend(member_context["members"]) # arrays - elif type == "SEQUENCE OF": + elif asn1_type_type == "SEQUENCE OF": # add field for array - array_name = asn1["name"] if "name" in asn1 else "array" - array_type = asn1['element']['type'] + array_name = asn1_type_info["name"] if "name" in asn1_type_info else "array" + array_type = asn1_type_info['element']['type'] if array_type == "RegionalExtension": - warnings.warn(f"Handling of 'RegionalExtension' in '{t_name}' not yet supported.") + warnings.warn(f"Handling of 'RegionalExtension' in '{asn1_type_name}' not yet supported.") return None member_context = { - "t_name": array_type, - "type": f"{array_type}[]", - "type_snake": f"{camel2snake(array_type)}[]", - "name": validRosField(camel2snake(array_name)), - "name_cc": validCField(array_name), + "asn1_type_name": array_type, + "ros_msg_type": f"{validRosType(array_type)}[]", + "ros2_msg_type_file_name": f"{validRosTypeHeader(array_type)}", + "ros_field_name": validRosField(array_name), + "c_field_name": validCFieldAsGenByAsn1c(array_name), "constants": [] } # add constants for size limits - if "size" in asn1 and isinstance(asn1["size"][0], tuple): - min_size = asn1["size"][0][0] - max_size = asn1["size"][0][1] + if "size" in asn1_type_info and isinstance(asn1_type_info["size"][0], tuple): + min_size = asn1_type_info["size"][0][0] + max_size = asn1_type_info["size"][0][1] ros_type = simplestRosIntegerType(min_size, max_size) min_size_constant_name = "MIN_SIZE" max_size_constant_name = "MAX_SIZE" - if "name" in asn1: - min_size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{min_size_constant_name}", is_const=True) - max_size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{max_size_constant_name}", is_const=True) + if "name" in asn1_type_info: + min_size_constant_name = validRosField(f"{asn1_type_info['name']}_{min_size_constant_name}", is_const=True) + max_size_constant_name = validRosField(f"{asn1_type_info['name']}_{max_size_constant_name}", is_const=True) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(min_size_constant_name, is_const=True), - "value": min_size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(min_size_constant_name, is_const=True), + "ros_value": min_size }) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(max_size_constant_name, is_const=True), - "value": max_size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(max_size_constant_name, is_const=True), + "ros_value": max_size }) - elif "size" in asn1 and isinstance(asn1["size"][0], int): - size = asn1["size"][0] + elif "size" in asn1_type_info and isinstance(asn1_type_info["size"][0], int): + size = asn1_type_info["size"][0] ros_type = simplestRosIntegerType(size, size) size_constant_name = "SIZE" - if "name" in asn1: - size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{size_constant_name}", is_const=True) + if "name" in asn1_type_info: + size_constant_name = validRosField(f"{asn1_type_info['name']}_{size_constant_name}", is_const=True) member_context["constants"].append({ - "type": ros_type, - "name": validRosField(size_constant_name, is_const=True), - "value": size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(size_constant_name, is_const=True), + "ros_value": size }) context["members"].append(member_context) # enums - elif type == "ENUMERATED": + elif asn1_type_type == "ENUMERATED": # choose simplest possible integer type - values = [val[1] for val in asn1["values"] if val is not None] + values = [val[1] for val in asn1_type_info["values"] if val is not None] min_value = min(values) max_value = max(values) ros_type = simplestRosIntegerType(min_value, max_value) # add field for active value member_context = { - "type": ros_type, - "name": "value", + "ros_msg_type": validRosType(ros_type), + "ros_field_name": "value", "constants": [], } # add constants for all values - for val in asn1["values"]: + for val in asn1_type_info["values"]: if val is None: continue member_context["constants"].append({ - "type": ros_type, - "name": validRosField(camel2SNAKE(val[0]), is_const=True), - "value": val[1] + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(val[0], is_const=True), + "ros_value": val[1] }) context["members"].append(member_context) # custom types - elif type in asn1_types: - - if type == "RegionalExtension": - warnings.warn(f"Handling of 'RegionalExtension' in '{t_name}' not yet supported.") + elif asn1_type_type in asn1_types: + + if asn1_type_type == "RegionalExtension": + warnings.warn(f"Handling of 'RegionalExtension' in '{asn1_type_name}' not yet supported.") return None - name_cc = asn1["name"] if "name" in asn1 else "value" - name = camel2snake(name_cc) + name = asn1_type_info["name"] if "name" in asn1_type_info else "value" context["members"].append({ - "t_name": type, - "type": validRosType(type), - "name": validRosField(camel2snake(name)), - "name_cc": validCField(name_cc), + "asn1_type_name": asn1_type_type, + "ros_msg_type": validRosType(asn1_type_type), + "ros_field_name": validRosField(name), + "c_field_name": validCFieldAsGenByAsn1c(name), "constants": [] }) # handle size in custom types - if "size" in asn1 and isinstance(asn1["size"][0], tuple): - min_size = asn1["size"][0][0] - max_size = asn1["size"][0][1] + if "size" in asn1_type_info and isinstance(asn1_type_info["size"][0], tuple): + min_size = asn1_type_info["size"][0][0] + max_size = asn1_type_info["size"][0][1] ros_type = simplestRosIntegerType(min_size, max_size) min_size_constant_name = "MIN_SIZE" max_size_constant_name = "MAX_SIZE" - if "name" in asn1: - min_size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{min_size_constant_name}", is_const=True) - max_size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{max_size_constant_name}", is_const=True) + if "name" in asn1_type_info: + min_size_constant_name = validRosField(f"{asn1_type_info['name']}_{min_size_constant_name}", is_const=True) + max_size_constant_name = validRosField(f"{asn1_type_info['name']}_{max_size_constant_name}", is_const=True) context["members"][0]["constants"].append({ - "type": ros_type, - "name": validRosField(min_size_constant_name, is_const=True), - "value": min_size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(min_size_constant_name, is_const=True), + "ros_value": min_size }) context["members"][0]["constants"].append({ - "type": ros_type, - "name": validRosField(max_size_constant_name, is_const=True), - "value": max_size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(max_size_constant_name, is_const=True), + "ros_value": max_size }) - elif "size" in asn1 and isinstance(asn1["size"][0], int): - size = asn1["size"][0] + elif "size" in asn1_type_info and isinstance(asn1_type_info["size"][0], int): + size = asn1_type_info["size"][0] ros_type = simplestRosIntegerType(size, size) size_constant_name = "SIZE" - if "name" in asn1: - size_constant_name = validRosField(f"{camel2SNAKE(asn1['name'])}_{size_constant_name}", is_const=True) + if "name" in asn1_type_info: + size_constant_name = validRosField(f"{asn1_type_info['name']}_{size_constant_name}", is_const=True) context["members"][0]["constants"].append({ - "type": ros_type, - "name": validRosField(size_constant_name, is_const=True), - "value": size + "ros_msg_type": validRosType(ros_type), + "ros_field_name": validRosField(size_constant_name, is_const=True), + "ros_value": size }) - elif type == "NULL": + elif asn1_type_type == "NULL": pass else: - warnings.warn(f"Cannot handle type '{type}'") + warnings.warn(f"Cannot handle type '{asn1_type_type}'") return context diff --git a/utils/codegen/codegen-py/asn1ToConversionHeader.py b/utils/codegen/codegen-py/asn1ToConversionHeader.py index 3c8a53a9..853657d0 100755 --- a/utils/codegen/codegen-py/asn1ToConversionHeader.py +++ b/utils/codegen/codegen-py/asn1ToConversionHeader.py @@ -108,15 +108,15 @@ def asn1TypeToConversionHeader(type_name: str, asn1_type: Dict, asn1_types: Dict # add etsi type to context jinja_context["etsi_type"] = etsi_type - + # add a dict entry for unique and sorted members (used for includes) seen = set() unique_sorted_members = [] for member in jinja_context["members"]: - if "t_name" in member and member["t_name"] not in seen: + if "asn1_type_name" in member and member["asn1_type_name"] not in seen: unique_sorted_members.append(member) - seen.add(member["t_name"]) - jinja_context["unique_sorted_members"] = sorted(unique_sorted_members, key=lambda member: member["t_name"]) + seen.add(member["asn1_type_name"]) + jinja_context["unique_sorted_members"] = sorted(unique_sorted_members, key=lambda member: member["asn1_type_name"]) # render jinja template with context header = jinja_template.render(jinja_context) @@ -151,16 +151,16 @@ def findDependenciesOfConversionHeaders(parent_file_path: str, type: str, file_l with open(parent_file_path, 'r') as file: lines = file.readlines() for line in lines: - + if line.startswith(f"#include +#include {% for member in unique_sorted_members -%} -{%- if member.name != "choice" -%} -#include +{%- if member.ros_field_name != "choice" -%} +#include {% endif -%} {%- endfor -%} #ifdef ROS1 -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs; #else -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs::msg; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs::msg; #endif -namespace etsi_its_{{ etsi_type }}_conversion { +namespace etsi_its_{{etsi_type}}_conversion { -void toRos_{{ t_name }}(const {{ etsi_type }}_{{ t_name }}_t& in, {{ etsi_type}}_msgs::{{ t_name }}& out) { +void toRos_{{ros_msg_type}}(const {{etsi_type}}_{{asn1_type_name}}_t& in, {{etsi_type}}_msgs::{{ros_msg_type}}& out) { switch (in.present) { {%- for member in members %} -{%- if member.name != "choice" -%} +{%- if member.ros_field_name != "choice" -%} {% for const in member.constants %} - case {{etsi_type}}_{{ t_name }}_PR_{{ member.name_cc }}: - toRos_{{ member.type|replace("[]", "") }}(in.choice.{{ member.name_cc }}, out.{{ member.name }}); - out.choice = {{ etsi_type}}_msgs::{{ t_name }}::{{ const.name }}; + case {{etsi_type}}_{{asn1_type_name}}_PR_{{member.c_field_name}}: + toRos_{{member.ros_msg_type|replace("[]", "")}}(in.choice.{{member.c_field_name}}, out.{{member.ros_field_name}}); + out.choice = {{etsi_type}}_msgs::{{ros_msg_type}}::{{const.ros_field_name}}; break; {%- endfor %} {%- endif %} @@ -59,16 +59,16 @@ void toRos_{{ t_name }}(const {{ etsi_type }}_{{ t_name }}_t& in, {{ etsi_type}} } } -void toStruct_{{ t_name }}(const {{ etsi_type}}_msgs::{{ t_name }}& in, {{ etsi_type }}_{{ t_name }}_t& out) { - memset(&out, 0, sizeof({{etsi_type}}_{{ t_name }}_t)); +void toStruct_{{ros_msg_type}}(const {{etsi_type}}_msgs::{{ros_msg_type}}& in, {{etsi_type}}_{{asn1_type_name}}_t& out) { + memset(&out, 0, sizeof({{etsi_type}}_{{asn1_type_name}}_t)); switch (in.choice) { {%- for member in members %} -{%- if member.name != "choice" -%} +{%- if member.ros_field_name != "choice" -%} {% for const in member.constants %} - case {{ etsi_type }}_msgs::{{ t_name }}::{{ const.name }}: - toStruct_{{ member.type|replace("[]", "") }}(in.{{ member.name }}, out.choice.{{ member.name_cc }}); - out.present = {{etsi_type}}_{{ t_name }}_PR::{{etsi_type}}_{{ t_name }}_PR_{{ member.name_cc }}; + case {{etsi_type}}_msgs::{{ros_msg_type}}::{{const.ros_field_name}}: + toStruct_{{member.ros_msg_type|replace("[]", "")}}(in.{{member.ros_field_name}}, out.choice.{{member.c_field_name}}); + out.present = {{etsi_type}}_{{asn1_type_name}}_PR::{{etsi_type}}_{{asn1_type_name}}_PR_{{member.c_field_name}}; break; {%- endfor %} {%- endif %} diff --git a/utils/codegen/codegen-py/templates/convertCustomType.h.jinja2 b/utils/codegen/codegen-py/templates/convertCustomType.h.jinja2 index ae485187..234720ba 100644 --- a/utils/codegen/codegen-py/templates/convertCustomType.h.jinja2 +++ b/utils/codegen/codegen-py/templates/convertCustomType.h.jinja2 @@ -26,31 +26,31 @@ SOFTWARE. #pragma once -#include +#include {% for member in members -%} -#include +#include {% endfor -%} #ifdef ROS1 -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs; #else -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs::msg; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs::msg; #endif -namespace etsi_its_{{ etsi_type }}_conversion { +namespace etsi_its_{{etsi_type}}_conversion { -void toRos_{{ t_name }}(const {{ etsi_type }}_{{ t_name }}_t& in, {{ etsi_type}}_msgs::{{ t_name }}& out) { +void toRos_{{ros_msg_type}}(const {{etsi_type}}_{{asn1_type_name}}_t& in, {{etsi_type}}_msgs::{{ros_msg_type}}& out) { {%- for member in members %} - toRos_{{ member.type }}(in, out.{{ member.name_cc }}); + toRos_{{member.ros_msg_type}}(in, out.{{member.c_field_name}}); {% endfor -%} } -void toStruct_{{ t_name }}(const {{ etsi_type}}_msgs::{{ t_name }}& in, {{ etsi_type }}_{{ t_name }}_t& out) { - memset(&out, 0, sizeof({{ etsi_type}}_{{ t_name }}_t)); +void toStruct_{{ros_msg_type}}(const {{etsi_type}}_msgs::{{ros_msg_type}}& in, {{etsi_type}}_{{asn1_type_name}}_t& out) { + memset(&out, 0, sizeof({{etsi_type}}_{{asn1_type_name}}_t)); {% for member in members %} - toStruct_{{ member.type }}(in.{{ member.name }}, out); + toStruct_{{member.ros_msg_type}}(in.{{member.ros_field_name}}, out); {% endfor -%} } diff --git a/utils/codegen/codegen-py/templates/convertEnumeratedType.h.jinja2 b/utils/codegen/codegen-py/templates/convertEnumeratedType.h.jinja2 index ff1db904..e40b0fa5 100644 --- a/utils/codegen/codegen-py/templates/convertEnumeratedType.h.jinja2 +++ b/utils/codegen/codegen-py/templates/convertEnumeratedType.h.jinja2 @@ -26,25 +26,25 @@ SOFTWARE. #pragma once -#include +#include #ifdef ROS1 -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs; #else -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs::msg; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs::msg; #endif -namespace etsi_its_{{ etsi_type }}_conversion { +namespace etsi_its_{{etsi_type}}_conversion { -void toRos_{{ t_name }}(const {{ etsi_type }}_{{ t_name }}_t& in, {{ etsi_type}}_msgs::{{ t_name }}& out) { +void toRos_{{ros_msg_type}}(const {{etsi_type}}_{{asn1_type_name}}_t& in, {{etsi_type}}_msgs::{{ros_msg_type}}& out) { out.value = in; } -void toStruct_{{ t_name }}(const {{ etsi_type}}_msgs::{{ t_name }}& in, {{ etsi_type }}_{{ t_name }}_t& out) { - memset(&out, 0, sizeof({{etsi_type}}_{{ t_name }}_t)); +void toStruct_{{ros_msg_type}}(const {{etsi_type}}_msgs::{{ros_msg_type}}& in, {{etsi_type}}_{{asn1_type_name}}_t& out) { + memset(&out, 0, sizeof({{etsi_type}}_{{asn1_type_name}}_t)); out = in.value; } diff --git a/utils/codegen/codegen-py/templates/convertPrimitiveType.h.jinja2 b/utils/codegen/codegen-py/templates/convertPrimitiveType.h.jinja2 index eb4984ec..ec6025d6 100644 --- a/utils/codegen/codegen-py/templates/convertPrimitiveType.h.jinja2 +++ b/utils/codegen/codegen-py/templates/convertPrimitiveType.h.jinja2 @@ -26,34 +26,34 @@ SOFTWARE. #pragma once -#include -#include -#include +#include +#include +#include #ifdef ROS1 -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs; #else -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs::msg; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs::msg; #endif -namespace etsi_its_{{ etsi_type }}_conversion { +namespace etsi_its_{{etsi_type}}_conversion { -void toRos_{{ t_name_camel }}(const {{etsi_type}}_{{ t_name|replace("-", "_") }}_t& in, {{ etsi_type}}_msgs::{{ t_name_camel }}& out) { +void toRos_{{ros_msg_type}}(const {{etsi_type}}_{{asn1_type_name|replace("-", "_")}}_t& in, {{etsi_type}}_msgs::{{ros_msg_type}}& out) { {%- for member in members %} - etsi_its_primitives_conversion::toRos_{{ type }}(in, out.{{ member.name }}); + etsi_its_primitives_conversion::toRos_{{asn1_type_type}}(in, out.{{member.ros_field_name}}); {%- if member.has_bits_unused %} out.bits_unused = in.bits_unused; {%- endif %} {%- endfor %} } -void toStruct_{{ t_name_camel }}(const {{ etsi_type}}_msgs::{{ t_name_camel }}& in, {{ etsi_type}}_{{ t_name|replace("-", "_") }}_t& out) { +void toStruct_{{ros_msg_type}}(const {{etsi_type}}_msgs::{{ros_msg_type}}& in, {{etsi_type}}_{{asn1_type_name|replace("-", "_")}}_t& out) { {%- for member in members %} - memset(&out, 0, sizeof({{ etsi_type}}_{{ t_name|replace("-", "_") }}_t)); + memset(&out, 0, sizeof({{etsi_type}}_{{asn1_type_name|replace("-", "_")}}_t)); - etsi_its_primitives_conversion::toStruct_{{ type }}(in.{{ member.name }}, out); + etsi_its_primitives_conversion::toStruct_{{asn1_type_type}}(in.{{member.ros_field_name}}, out); {%- if member.has_bits_unused %} out.bits_unused = in.bits_unused; {%- endif %} diff --git a/utils/codegen/codegen-py/templates/convertSequenceOfType.h.jinja2 b/utils/codegen/codegen-py/templates/convertSequenceOfType.h.jinja2 index 17f7dcc0..00063d9b 100644 --- a/utils/codegen/codegen-py/templates/convertSequenceOfType.h.jinja2 +++ b/utils/codegen/codegen-py/templates/convertSequenceOfType.h.jinja2 @@ -28,45 +28,45 @@ SOFTWARE. #include -#include -#include +#include +#include {% for member in members -%} -#include -#include +#include +#include {% endfor -%} #ifdef ROS1 {% for member in members -%} -#include +#include {% endfor -%} -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs; #else {% for member in members -%} -#include +#include {% endfor -%} -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs::msg; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs::msg; #endif -namespace etsi_its_{{ etsi_type }}_conversion { +namespace etsi_its_{{etsi_type}}_conversion { -void toRos_{{ t_name }}(const {{ etsi_type }}_{{ t_name }}_t& in, {{ etsi_type}}_msgs::{{ t_name }}& out) { +void toRos_{{ros_msg_type}}(const {{etsi_type}}_{{asn1_type_name}}_t& in, {{etsi_type}}_msgs::{{ros_msg_type}}& out) { {%- for member in members %} for (int i = 0; i < in.list.count; ++i) { - {{ etsi_type}}_msgs::{{ member.type|replace("[]", "") }} el; - toRos_{{ member.type|replace("[]", "") }}(*(in.list.array[i]), el); + {{etsi_type}}_msgs::{{member.ros_msg_type|replace("[]", "")}} el; + toRos_{{member.ros_msg_type|replace("[]", "")}}(*(in.list.array[i]), el); out.array.push_back(el); } {% endfor -%} } -void toStruct_{{ t_name }}(const {{ etsi_type}}_msgs::{{ t_name }}& in, {{ etsi_type }}_{{ t_name }}_t& out) { - memset(&out, 0, sizeof({{etsi_type}}_{{ t_name }}_t)); +void toStruct_{{ros_msg_type}}(const {{etsi_type}}_msgs::{{ros_msg_type}}& in, {{etsi_type}}_{{asn1_type_name}}_t& out) { + memset(&out, 0, sizeof({{etsi_type}}_{{asn1_type_name}}_t)); {% for member in members %} for (int i = 0; i < in.array.size(); ++i) { - {{etsi_type}}_{{ member.type|replace("[]", "") }}_t* el = ({{etsi_type}}_{{ member.type|replace("[]", "") }}_t*) calloc(1, sizeof({{etsi_type}}_{{ member.type|replace("[]", "") }}_t)); - toStruct_{{ member.type|replace("[]", "") }}(in.array[i], *el); + {{etsi_type}}_{{member.ros_msg_type|replace("[]", "")}}_t* el = ({{etsi_type}}_{{member.ros_msg_type|replace("[]", "")}}_t*) calloc(1, sizeof({{etsi_type}}_{{member.ros_msg_type|replace("[]", "")}}_t)); + toStruct_{{member.ros_msg_type|replace("[]", "")}}(in.array[i], *el); if (asn_sequence_add(&out, el)) throw std::invalid_argument("Failed to add to A_SEQUENCE_OF"); } {%- endfor %} diff --git a/utils/codegen/codegen-py/templates/convertSequenceType.h.jinja2 b/utils/codegen/codegen-py/templates/convertSequenceType.h.jinja2 index a2aace56..24c3b9c7 100644 --- a/utils/codegen/codegen-py/templates/convertSequenceType.h.jinja2 +++ b/utils/codegen/codegen-py/templates/convertSequenceType.h.jinja2 @@ -26,85 +26,85 @@ SOFTWARE. #pragma once -#include +#include {% for member in unique_sorted_members -%} {% if member.is_primitive -%} -#include -#include +#include +#include {% elif not member.is_choice_var -%} -#include +#include {% endif -%} {% endfor -%} #ifdef ROS1 -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs; #else -#include -namespace {{ etsi_type }}_msgs = etsi_its_{{ etsi_type }}_msgs::msg; +#include +namespace {{etsi_type}}_msgs = etsi_its_{{etsi_type}}_msgs::msg; #endif -namespace etsi_its_{{ etsi_type }}_conversion { +namespace etsi_its_{{etsi_type}}_conversion { -void toRos_{{ t_name_camel }}(const {{ etsi_type }}_{{ t_name|replace("-", "_") }}_t& in, {{ etsi_type}}_msgs::{{ t_name_camel }}& out) { +void toRos_{{ros_msg_type}}(const {{etsi_type}}_{{asn1_type_name|replace("-", "_")}}_t& in, {{etsi_type}}_msgs::{{ros_msg_type}}& out) { {%- for member in members -%} {% if member.optional or member.default %} - if (in.{{ member.name_cc }}) { + if (in.{{member.c_field_name}}) { {%- if member.is_primitive %} - etsi_its_primitives_conversion::toRos_{{ member.asn1_type }}(*in.{{ member.name_cc }}, out.{{ member.name }}); + etsi_its_primitives_conversion::toRos_{{member.asn1_type_name}}(*in.{{member.c_field_name}}, out.{{member.ros_field_name}}); {%- else %} - toRos_{{ member.type|replace("[]", "") }}(*in.{{ member.name_cc }}, out.{{ member.name }}); + toRos_{{member.ros_msg_type|replace("[]", "")}}(*in.{{member.c_field_name}}, out.{{member.ros_field_name}}); {%- endif %} {%- if member.optional %} - out.{{ member.name }}_is_present = true; + out.{{member.ros_field_name}}_is_present = true; {%- endif %} } {%- elif not member.is_choice_var %} {%- if member.is_primitive %} - etsi_its_primitives_conversion::toRos_{{ member.asn1_type }}(in.{{ member.name_cc }}, out.{{ member.name }}); + etsi_its_primitives_conversion::toRos_{{member.asn1_type_name}}(in.{{member.c_field_name}}, out.{{member.ros_field_name}}); {%- elif member.is_choice %} - if (in.{{ member.choice_name }}.present == {{etsi_type}}_{{ t_name }}__{{ member.choice_name }}_PR::{{etsi_type}}_{{ t_name }}__{{ member.choice_name }}_PR_{{ member.choice_option_name }}) { - toRos_{{ member.type }}(in.{{ member.choice_name }}.choice.{{ member.choice_option_name }}, out.{{ member.name }}); - out.{{ member.choice_var_name }} = {{ etsi_type}}_msgs::{{ t_name }}::{{ member.constants[0].name }}; + if (in.{{member.choice_name}}.present == {{etsi_type}}_{{asn1_type_name}}__{{member.choice_name}}_PR::{{etsi_type}}_{{asn1_type_name}}__{{member.choice_name}}_PR_{{member.choice_option_name}}) { + toRos_{{member.ros_msg_type}}(in.{{member.choice_name}}.choice.{{member.choice_option_name}}, out.{{member.ros_field_name}}); + out.{{member.choice_var_name}} = {{etsi_type}}_msgs::{{asn1_type_name}}::{{member.constants[0].ros_field_name}}; } {%- else %} - toRos_{{ member.type|replace("[]", "") }}(in.{{ member.name_cc }}, out.{{ member.name }}); + toRos_{{member.ros_msg_type|replace("[]", "")}}(in.{{member.c_field_name}}, out.{{member.ros_field_name}}); {%- endif -%} {%- endif -%} {% endfor %} } -void toStruct_{{ t_name_camel }}(const {{ etsi_type}}_msgs::{{ t_name_camel }}& in, {{ etsi_type }}_{{ t_name|replace("-", "_") }}_t& out) { - memset(&out, 0, sizeof({{etsi_type}}_{{ t_name|replace("-", "_") }}_t)); +void toStruct_{{ros_msg_type}}(const {{etsi_type}}_msgs::{{ros_msg_type}}& in, {{etsi_type}}_{{asn1_type_name|replace("-", "_")}}_t& out) { + memset(&out, 0, sizeof({{etsi_type}}_{{asn1_type_name|replace("-", "_")}}_t)); {% for member in members -%} {% if member.optional %} - if (in.{{ member.name }}_is_present) { + if (in.{{member.ros_field_name}}_is_present) { {%- if member.is_primitive %} - out.{{member.name_cc}} = ({{ member.asn1_type }}_t*) calloc(1, sizeof({{ member.asn1_type }}_t)); - etsi_its_primitives_conversion::toStruct_{{ member.asn1_type }}(in.{{ member.name }}, *out.{{member.name_cc}}); + out.{{member.c_field_name}} = ({{member.asn1_type_name}}_t*) calloc(1, sizeof({{member.asn1_type_name}}_t)); + etsi_its_primitives_conversion::toStruct_{{member.asn1_type_name}}(in.{{member.ros_field_name}}, *out.{{member.c_field_name}}); {%- else %} - out.{{member.name_cc}} = ({{etsi_type}}_{{member.t_name|replace("-", "_")|replace("[]", "")}}_t*) calloc(1, sizeof({{etsi_type}}_{{member.t_name|replace("-", "_")|replace("[]", "")}}_t)); - toStruct_{{ member.type|replace("[]", "") }}(in.{{ member.name }}, *out.{{member.name_cc}}); + out.{{member.c_field_name}} = ({{etsi_type}}_{{member.asn1_type_name|replace("-", "_")|replace("[]", "")}}_t*) calloc(1, sizeof({{etsi_type}}_{{member.asn1_type_name|replace("-", "_")|replace("[]", "")}}_t)); + toStruct_{{member.ros_msg_type|replace("[]", "")}}(in.{{member.ros_field_name}}, *out.{{member.c_field_name}}); {%- endif %} } {%- elif member.default %} {%- if member.is_primitive %} - out.{{member.name_cc}} = ({{ member.asn1_type }}_t*) calloc(1, sizeof({{ member.asn1_type }}_t)); - etsi_its_primitives_conversion::toStruct_{{ member.asn1_type }}(in.{{ member.name }}, *out.{{member.name_cc}}); + out.{{member.c_field_name}} = ({{member.asn1_type_name}}_t*) calloc(1, sizeof({{member.asn1_type_name}}_t)); + etsi_its_primitives_conversion::toStruct_{{member.asn1_type_name}}(in.{{member.ros_field_name}}, *out.{{member.c_field_name}}); {%- else %} - out.{{member.name_cc}} = ({{etsi_type}}_{{ member.type|replace("[]", "") }}_t*) calloc(1, sizeof({{etsi_type}}_{{ member.type|replace("[]", "") }}_t)); - toStruct_{{ member.type|replace("[]", "") }}(in.{{ member.name }}, *out.{{member.name_cc}}); + out.{{member.c_field_name}} = ({{etsi_type}}_{{member.ros_msg_type|replace("[]", "")}}_t*) calloc(1, sizeof({{etsi_type}}_{{member.ros_msg_type|replace("[]", "")}}_t)); + toStruct_{{member.ros_msg_type|replace("[]", "")}}(in.{{member.ros_field_name}}, *out.{{member.c_field_name}}); {%- endif %} {%- elif not member.is_choice_var %} {%- if member.is_primitive %} - etsi_its_primitives_conversion::toStruct_{{ member.asn1_type }}(in.{{ member.name }}, out.{{ member.name_cc }}); + etsi_its_primitives_conversion::toStruct_{{member.asn1_type_name}}(in.{{member.ros_field_name}}, out.{{member.c_field_name}}); {%- elif member.is_choice %} - if (in.{{ member.choice_var_name }} == {{ etsi_type}}_msgs::{{ t_name }}::{{ member.constants[0].name }}) { - toStruct_{{ member.type }}(in.{{ member.name }}, out.{{ member.choice_name }}.choice.{{ member.choice_option_name }}); - out.{{ member.choice_name }}.present = {{etsi_type}}_{{ t_name }}__{{ member.choice_name }}_PR::{{etsi_type}}_{{ t_name }}__{{ member.choice_name }}_PR_{{ member.choice_option_name }}; + if (in.{{member.choice_var_name}} == {{etsi_type}}_msgs::{{asn1_type_name}}::{{member.constants[0].ros_field_name}}) { + toStruct_{{member.ros_msg_type}}(in.{{member.ros_field_name}}, out.{{member.choice_name}}.choice.{{member.choice_option_name}}); + out.{{member.choice_name}}.present = {{etsi_type}}_{{asn1_type_name}}__{{member.choice_name}}_PR::{{etsi_type}}_{{asn1_type_name}}__{{member.choice_name}}_PR_{{member.choice_option_name}}; } {%- else %} - toStruct_{{ member.type|replace("[]", "") }}(in.{{ member.name }}, out.{{ member.name_cc }}); + toStruct_{{member.ros_msg_type|replace("[]", "")}}(in.{{member.ros_field_name}}, out.{{member.c_field_name}}); {%- endif -%} {%- endif -%} {% endfor %} diff --git a/utils/codegen/codegen-py/testNaming.py b/utils/codegen/codegen-py/testNaming.py new file mode 100755 index 00000000..f5d6f8cc --- /dev/null +++ b/utils/codegen/codegen-py/testNaming.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +# ============================================================================== +# MIT License +# +# Copyright (c) 2023-2024 Institute for Automotive Engineering (ika), RWTH Aachen University +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ============================================================================== + +import unittest + +from asn1CodeGenerationUtils import validCFieldAsGenByAsn1c, validRosField, validRosType + + +class TestNaming(unittest.TestCase): + + def test_validCField(self): + self.assertEqual(validCFieldAsGenByAsn1c("a"), "a") + self.assertEqual(validCFieldAsGenByAsn1c("field-name"), "field_name") + self.assertEqual(validCFieldAsGenByAsn1c("class"), "Class") + self.assertEqual(validCFieldAsGenByAsn1c("long"), "Long") + + def test_validRosType(self): + self.assertEqual(validRosType("a"), "A") + self.assertEqual(validRosType("abc"), "Abc") + self.assertEqual(validRosType("typeName"), "TypeName") + self.assertEqual(validRosType("TypeName"), "TypeName") + self.assertEqual(validRosType("Type_Name"), "TypeName") + self.assertEqual(validRosType("TYPE_NAME"), "TYPENAME") + self.assertEqual(validRosType("Type_NAME_123"), "TypeNAME123") + self.assertEqual(validRosType("1TypeName"), "A1TypeName") + self.assertEqual(validRosType("uint32[]"), "uint32[]") + + def test_validRosField(self): + self.assertEqual(validRosField("a"), "a") + self.assertEqual(validRosField("B"), "b") + self.assertEqual(validRosField("abc"), "abc") + self.assertEqual(validRosField("ABC"), "abc") + self.assertEqual(validRosField("a_b_c_"), "a_b_c_") + self.assertEqual(validRosField("a-b-c"), "a_b_c") + self.assertEqual(validRosField("fieldName"), "field_name") + self.assertEqual(validRosField("FieldName"), "field_name") + self.assertEqual(validRosField("FIELD_NAME"), "field_name") + self.assertEqual(validRosField("field-name"), "field_name") + self.assertEqual(validRosField("FieldName123"), "field_name123") + self.assertEqual(validRosField("FieldABCName"), "field_abc_name") + self.assertEqual(validRosField("FieldABC123Name"), "field_abc123_name") + self.assertEqual(validRosField("class"), "cls") + self.assertEqual(validRosField("long"), "lon") + + def test_validRosFieldConst(self): + self.assertEqual(validRosField("a", is_const=True), "A") + self.assertEqual(validRosField("B", is_const=True), "B") + self.assertEqual(validRosField("abc", is_const=True), "ABC") + self.assertEqual(validRosField("ABC", is_const=True), "ABC") + self.assertEqual(validRosField("a_b_c_", is_const=True), "A_B_C_") + self.assertEqual(validRosField("a-b-c", is_const=True), "A_B_C") + self.assertEqual(validRosField("fieldName", is_const=True), "FIELD_NAME") + self.assertEqual(validRosField("FieldName", is_const=True), "FIELD_NAME") + self.assertEqual(validRosField("FIELD_NAME", is_const=True), "FIELD_NAME") + self.assertEqual(validRosField("field-name", is_const=True), "FIELD_NAME") + self.assertEqual(validRosField("FieldName123", is_const=True), "FIELD_NAME123") + self.assertEqual(validRosField("FieldABCName", is_const=True), "FIELD_ABC_NAME") + self.assertEqual(validRosField("FieldABC123Name", is_const=True), "FIELD_ABC123_NAME") + + +if __name__ == "__main__": + unittest.main()