1 # Copyright 2023 highstreet technologies GmbH
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
18 A Class representing an O-RAN radio unit (ORanRu)
20 import xml.etree.ElementTree as ET
21 from typing import Any, cast
23 from network_generation.model.python.nr_cell_du import NrCellDu
24 from network_generation.model.python.o_ran_du import ORanDu
25 from network_generation.model.python.o_ran_node import IORanNode, ORanNode
26 from network_generation.model.python.o_ran_termination_point import (
31 # Define the "IORanRu" interface
32 class IORanRu(IORanNode):
38 default_value: IORanRu = cast(
42 **{"cellCount": 1, "ruAngle": 120, "ruAzimuth": 0},
47 # Define an abstract O-RAN Node class
48 class ORanRu(ORanNode):
51 data: dict[str, Any] = cast(dict[str, Any], default_value),
52 **kwargs: dict[str, Any]
54 o_ran_ru_data: IORanRu = self._to_o_ran_ru_data(data)
55 super().__init__(cast(dict[str, Any], o_ran_ru_data), **kwargs)
56 self._cell_count: int = (
57 int(str(o_ran_ru_data["cellCount"]))
58 if o_ran_ru_data and "cellCount" in o_ran_ru_data
61 self._ru_angle: int = (
62 int(str(o_ran_ru_data["ruAngle"]))
63 if o_ran_ru_data and "ruAngle" in o_ran_ru_data
66 self._ru_azimuth: int = (
67 int(str(o_ran_ru_data["ruAzimuth"]))
68 if o_ran_ru_data and "ruAzimuth" in o_ran_ru_data
71 self._cells: list[NrCellDu] = self._create_cells()
72 name: str = self.name.replace("RU", "DU")
74 o_ran_du_data: dict[str, Any] = {
76 "geoLocation": self.parent.geo_location,
77 "position": self.parent.position,
78 "layout": self.layout,
79 "parent": self.parent.parent.parent,
81 self._oRanDu: ORanDu = ORanDu(o_ran_du_data)
83 def _to_o_ran_ru_data(self, data: dict[str, Any]) -> IORanRu:
84 result: IORanRu = default_value
85 for key, key_type in IORanRu.__annotations__.items():
87 result[key] = data[key] # type: ignore
90 def _create_cells(self) -> list[NrCellDu]:
91 result: list[NrCellDu] = []
93 self.parent.parent.parent.parent.parent.parent.configuration[
95 ]["nr-cell-du"]["cell-angle"]
97 for index in range(self._cell_count):
98 s: str = "00" + str(index)
100 [self.name.replace("RU", "NRCellDu"), s[len(s) - 2: len(s)]]
102 azimuth: int = index * cell_angle + self._ru_azimuth
107 "geoLocation": self.geo_location,
108 "position": self.position,
109 "layout": self.layout,
111 "cellAngle": cell_angle,
119 def cells(self) -> list[NrCellDu]:
123 def oRanDu(self) -> ORanDu:
126 def termination_points(self) -> list[ORanTerminationPoint]:
127 result: list[ORanTerminationPoint] = super().termination_points()
128 phy_tp: str = "-".join([self.name, "phy".upper()])
129 result.append(ORanTerminationPoint({"id": phy_tp, "name": phy_tp}))
130 for interface in ["ofhm", "ofhc", "ofhu", "ofhs"]:
131 id: str = "-".join([self.name, interface.upper()])
133 ORanTerminationPoint(
134 {"id": id, "name": id, "supporter": phy_tp, "parent": self}
137 for cell in self.cells:
138 result.extend(cell.termination_points())
141 def to_topology_nodes(self) -> list[dict[str, Any]]:
142 result: list[dict[str, Any]] = super().to_topology_nodes()
143 result.extend(self.oRanDu.to_topology_nodes())
146 def to_topology_links(self) -> list[dict[str, Any]]:
147 result: list[dict[str, Any]] = super().to_topology_links()
148 result.extend(self.oRanDu.to_topology_links())
149 for interface in ["phy", "ofhm", "ofhc", "ofhu", "ofhs"]:
150 link_id: str = "".join(
151 [interface, ":", self.name, "<->", self.oRanDu.name]
153 source_tp: str = "-".join([self.name, interface.upper()])
154 dest_tp: str = "-".join([self.oRanDu.name, interface.upper()])
159 "source-node": self.name,
160 "source-tp": source_tp,
163 "dest-node": self.oRanDu.name,
170 def toKml(self) -> ET.Element:
171 o_ran_ru: ET.Element = ET.Element("Folder")
172 open: ET.Element = ET.SubElement(o_ran_ru, "open")
174 name: ET.Element = ET.SubElement(o_ran_ru, "name")
175 name.text = self.name
176 for cell in self.cells:
177 o_ran_ru.append(cell.toKml())
180 def toSvg(self) -> ET.Element:
181 return ET.Element("to-be-implemented")