Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Paul Graydon
slapos
Commits
7a31af8e
Commit
7a31af8e
authored
Sep 06, 2024
by
Lu Xu
👀
Browse files
Options
Browse Files
Download
Plain Diff
software/ors-amarisoft: Move lopcomm to private repository
See merge request
!1635
parents
c3244027
35bc2685
Changes
19
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
28 additions
and
1313 deletions
+28
-1313
software/ors-amarisoft/buildout.hash.cfg
software/ors-amarisoft/buildout.hash.cfg
+3
-39
software/ors-amarisoft/cell/common.json
software/ors-amarisoft/cell/common.json
+0
-3
software/ors-amarisoft/instance.cfg
software/ors-amarisoft/instance.cfg
+0
-21
software/ors-amarisoft/ru/buildout.cfg
software/ors-amarisoft/ru/buildout.cfg
+0
-1
software/ors-amarisoft/ru/input-schema.json
software/ors-amarisoft/ru/input-schema.json
+0
-3
software/ors-amarisoft/ru/libinstance.jinja2.cfg
software/ors-amarisoft/ru/libinstance.jinja2.cfg
+0
-2
software/ors-amarisoft/ru/lopcomm/CreateProcessingEle.jinja2.xml
...e/ors-amarisoft/ru/lopcomm/CreateProcessingEle.jinja2.xml
+0
-11
software/ors-amarisoft/ru/lopcomm/buildout.cfg
software/ors-amarisoft/ru/lopcomm/buildout.cfg
+0
-39
software/ors-amarisoft/ru/lopcomm/config.jinja2.py
software/ors-amarisoft/ru/lopcomm/config.jinja2.py
+0
-19
software/ors-amarisoft/ru/lopcomm/cu_config.jinja2.xml
software/ors-amarisoft/ru/lopcomm/cu_config.jinja2.xml
+0
-132
software/ors-amarisoft/ru/lopcomm/input-schema.json
software/ors-amarisoft/ru/lopcomm/input-schema.json
+0
-64
software/ors-amarisoft/ru/lopcomm/libinstance.jinja2.cfg
software/ors-amarisoft/ru/lopcomm/libinstance.jinja2.cfg
+0
-314
software/ors-amarisoft/ru/lopcomm/ncclient_common.py
software/ors-amarisoft/ru/lopcomm/ncclient_common.py
+0
-222
software/ors-amarisoft/ru/lopcomm/reset-info.jinja2.py
software/ors-amarisoft/ru/lopcomm/reset-info.jinja2.py
+0
-39
software/ors-amarisoft/ru/lopcomm/reset.jinja2.py
software/ors-amarisoft/ru/lopcomm/reset.jinja2.py
+0
-17
software/ors-amarisoft/ru/lopcomm/software.jinja2.py
software/ors-amarisoft/ru/lopcomm/software.jinja2.py
+0
-104
software/ors-amarisoft/ru/lopcomm/stats.jinja2.py
software/ors-amarisoft/ru/lopcomm/stats.jinja2.py
+0
-81
software/ors-amarisoft/slaplte.jinja2
software/ors-amarisoft/slaplte.jinja2
+0
-11
software/ors-amarisoft/test/test.py
software/ors-amarisoft/test/test.py
+25
-191
No files found.
software/ors-amarisoft/buildout.hash.cfg
View file @
7a31af8e
...
...
@@ -16,7 +16,7 @@
[template]
filename = instance.cfg
md5sum =
2e30c07c6436895ac0bc6c177cf7013d
md5sum =
f096f3cbb414730a9f0d46b0c0f5eb22
[template-ors]
filename = instance-ors.cfg
...
...
@@ -24,7 +24,7 @@ md5sum = f5c76c3443b75569eb18503dce38e783
[slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2
md5sum =
871ade334f445e22d6cb473e4d4e3522
md5sum =
27c49897c9a3e4c260105534bed0132d
[ru_amarisoft-stats.jinja2.py]
_update_hash_filename_ = ru/amarisoft-stats.jinja2.py
...
...
@@ -36,44 +36,16 @@ md5sum = ab666fdfadbfc7d8a16ace38d295c883
[ru_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/libinstance.jinja2.cfg
md5sum =
2dda7713832be83d94522c7abb4901f9
md5sum =
7613c4decd4468ab5d826421aef955f1
[ru_sdr_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg
md5sum = b7906ca3a6b17963f78f680fc0842b74
[ru_lopcomm_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg
md5sum = c3bd882559ab9cd2a068519ea5d8c92e
[ru_sunwave_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg
md5sum = bc5d82b8737b6990674b280ef2774be7
[ru_lopcomm_ncclient_common.py]
_update_hash_filename_ = ru/lopcomm/ncclient_common.py
md5sum = 8dbe6a48fc0fca4f0cbd0c746be1aeda
[ru_lopcomm_stats.jinja2.py]
_update_hash_filename_ = ru/lopcomm/stats.jinja2.py
md5sum = b7ec0025a92e0947e4ac6abc4b06bf19
[ru_lopcomm_config.jinja2.py]
_update_hash_filename_ = ru/lopcomm/config.jinja2.py
md5sum = 122726666d147447171dcae9ebf8d093
[ru_lopcomm_reset-info.jinja2.py]
_update_hash_filename_ = ru/lopcomm/reset-info.jinja2.py
md5sum = 3d78df1993211efaabd3dc6f2ec8de30
[ru_lopcomm_reset.jinja2.py]
_update_hash_filename_ = ru/lopcomm/reset.jinja2.py
md5sum = 9741fbc99aaf768e9cc3ab48925dfee5
[ru_lopcomm_software.jinja2.py]
_update_hash_filename_ = ru/lopcomm/software.jinja2.py
md5sum = 2b08bb666c5f3ab287cdddbfdb4c9249
[ru_tapsplit]
_update_hash_filename_ = ru/tapsplit
md5sum = 700aab566289619fb83ac6f3b085d983
...
...
@@ -150,14 +122,6 @@ md5sum = f07c85916bcb7e4002c8edc3d087c1be
filename = config/ue.jinja2.cfg
md5sum = 62291a11fd36a42464901cdc81338687
[ru_lopcomm_CreateProcessingEle.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/CreateProcessingEle.jinja2.xml
md5sum = e435990eb0a0d4be41efa9bd16dce09b
[ru_lopcomm_cu_config.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/cu_config.jinja2.xml
md5sum = 346c911e1ac5e5001a39c8926b44c91e
[software.cfg.html]
_update_hash_filename_ = gadget/software.cfg.html
md5sum = 61a2f783fbf683a34aed3d13e00baca2
...
...
software/ors-amarisoft/cell/common.json
View file @
7a31af8e
...
...
@@ -105,9 +105,6 @@
{
"$ref"
:
"../ru/sdr/input-schema.json"
},
{
"$ref"
:
"../ru/lopcomm/input-schema.json"
},
{
"$ref"
:
"../ru/sunwave/input-schema.json"
}
...
...
software/ors-amarisoft/instance.cfg
View file @
7a31af8e
...
...
@@ -46,7 +46,6 @@ import-list =
rawfile slaplte.jinja2 ${slaplte.jinja2:target}
rawfile ru_libinstance.jinja2.cfg ${ru_libinstance.jinja2.cfg:target}
rawfile ru_sdr_libinstance.jinja2.cfg ${ru_sdr_libinstance.jinja2.cfg:target}
rawfile ru_lopcomm_libinstance.jinja2.cfg ${ru_lopcomm_libinstance.jinja2.cfg:target}
rawfile ru_sunwave_libinstance.jinja2.cfg ${ru_sunwave_libinstance.jinja2.cfg:target}
# activate eggs and modules used in jinja2 templates
...
...
@@ -158,16 +157,6 @@ extra-context =
raw sib23_template ${sib23.jinja2.asn:target}
raw ru_amarisoft_stats_template ${ru_amarisoft-stats.jinja2.py:target}
raw ru_amarisoft_rf_info_template ${ru_amarisoft-rf-info.jinja2.py:target}
raw ru_lopcomm_stats_template ${ru_lopcomm_stats.jinja2.py:target}
raw ru_lopcomm_config_template ${ru_lopcomm_config.jinja2.py:target}
raw ru_lopcomm_software_template ${ru_lopcomm_software.jinja2.py:target}
raw ru_lopcomm_reset_info_template ${ru_lopcomm_reset-info.jinja2.py:target}
raw ru_lopcomm_reset_template ${ru_lopcomm_reset.jinja2.py:target}
raw ru_lopcomm_CreateProcessingEle_template ${ru_lopcomm_CreateProcessingEle.jinja2.xml:target}
raw ru_lopcomm_cu_config_template ${ru_lopcomm_cu_config.jinja2.xml:target}
raw ru_lopcomm_cu_inactive_config_template ${ru_lopcomm_cu_config.jinja2.xml:target}
raw ru_lopcomm_firmware_path ${ru_lopcomm_firmware-dl:target}
raw ru_lopcomm_firmware_filename ${ru_lopcomm_firmware-dl:filename}
raw ru_tapsplit ${ru_tapsplit:target}
raw netcapdo ${netcapdo:exe}
raw openssl_location ${openssl:location}
...
...
@@ -217,16 +206,6 @@ extra-context =
raw ru_amarisoft_stats_template ${ru_amarisoft-stats.jinja2.py:target}
raw ru_amarisoft_rf_info_template ${ru_amarisoft-rf-info.jinja2.py:target}
raw ru_lopcomm_stats_template ${ru_lopcomm_stats.jinja2.py:target}
raw ru_lopcomm_config_template ${ru_lopcomm_config.jinja2.py:target}
raw ru_lopcomm_software_template ${ru_lopcomm_software.jinja2.py:target}
raw ru_lopcomm_reset_info_template ${ru_lopcomm_reset-info.jinja2.py:target}
raw ru_lopcomm_reset_template ${ru_lopcomm_reset.jinja2.py:target}
raw ru_lopcomm_CreateProcessingEle_template ${ru_lopcomm_CreateProcessingEle.jinja2.xml:target}
raw ru_lopcomm_cu_config_template ${ru_lopcomm_cu_config.jinja2.xml:target}
raw ru_lopcomm_cu_inactive_config_template ${ru_lopcomm_cu_config.jinja2.xml:target}
raw ru_lopcomm_firmware_path ${ru_lopcomm_firmware-dl:target}
raw ru_lopcomm_firmware_filename ${ru_lopcomm_firmware-dl:filename}
raw ru_tapsplit ${ru_tapsplit:target}
raw netcapdo ${netcapdo:exe}
raw ru_dnsmasq_template ${ru_dnsmasq.jinja2.cfg:target}
...
...
software/ors-amarisoft/ru/buildout.cfg
View file @
7a31af8e
...
...
@@ -3,7 +3,6 @@
[buildout]
extends =
sdr/buildout.cfg
lopcomm/buildout.cfg
sunwave/buildout.cfg
parts +=
...
...
software/ors-amarisoft/ru/input-schema.json
View file @
7a31af8e
...
...
@@ -6,9 +6,6 @@
{
"$ref"
:
"sdr/input-schema.json"
},
{
"$ref"
:
"lopcomm/input-schema.json"
},
{
"$ref"
:
"sunwave/input-schema.json"
}
...
...
software/ors-amarisoft/ru/libinstance.jinja2.cfg
View file @
7a31af8e
...
...
@@ -53,10 +53,8 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{%- set ierror = slaplte.ierror %}
{%- import 'ru_sdr_libinstance.jinja2.cfg' as rudrv_sdr with context %}
{%- import 'ru_lopcomm_libinstance.jinja2.cfg' as rudrv_lopcomm with context %}
{%- import 'ru_sunwave_libinstance.jinja2.cfg' as rudrv_sunwave with context %}
{%- set rudrv_dict = namespace(sdr=rudrv_sdr,
lopcomm=rudrv_lopcomm,
sunwave=rudrv_sunwave) %}
{%- set rudrv_init = {} %}
...
...
software/ors-amarisoft/ru/lopcomm/CreateProcessingEle.jinja2.xml
deleted
100644 → 0
View file @
c3244027
<config
xmlns=
"urn:ietf:params:xml:ns:netconf:base:1.0"
>
<processing-elements
xmlns=
"urn:o-ran:processing-element:1.0"
>
<transport-session-type>
CPRI-INTERFACE
</transport-session-type>
<ru-elements>
<name>
PE0
</name>
<transport-flow>
<interface-name>
eth1
</interface-name>
</transport-flow>
</ru-elements>
</processing-elements>
</config>
\ No newline at end of file
software/ors-amarisoft/ru/lopcomm/buildout.cfg
deleted
100644 → 0
View file @
c3244027
# ru/lopcomm/buildout.cfg provides software code for handling Lopcomm ORAN Radio Units.
[buildout]
parts +=
ru_lopcomm_ncclient_common.py
[ru_lopcomm_libinstance.jinja2.cfg]
<= download-base
[ru_lopcomm_config.jinja2.py]
<= download-base
[ru_lopcomm_reset-info.jinja2.py]
<= download-base
[ru_lopcomm_reset.jinja2.py]
<= download-base
[ru_lopcomm_stats.jinja2.py]
<= download-base
[ru_lopcomm_software.jinja2.py]
<= download-base
[ru_lopcomm_ncclient_common.py]
<= download-base
destination = ${buildout:directory}/ncclient_common.py
[ru_lopcomm_CreateProcessingEle.jinja2.xml]
<= download-base
[ru_lopcomm_cu_config.jinja2.xml]
<= download-base
[ru_lopcomm_firmware-dl]
recipe = slapos.recipe.build:download
url = https://lab.nexedi.com/nexedi/ors-utils/raw/master/lopcomm-firmware/${:filename}
filename = PR.PRM61C70V1005.005.tar.gz
md5sum = 62281d0be42feac94e843e1850ba6e09
software/ors-amarisoft/ru/lopcomm/config.jinja2.py
deleted
100644 → 0
View file @
c3244027
#!{{ python_path }}
import
time
import
sys
sys
.
path
.
append
({{
repr
(
buildout_directory_path
)
}})
from
ncclient_common
import
LopcommNetconfClient
if
__name__
==
'__main__'
:
nc
=
LopcommNetconfClient
(
log_file
=
"{{ log_file }}"
)
while
True
:
try
:
nc
.
connect
(
"{{ netaddr.IPAddress(vtap.gateway) }}"
,
830
,
"oranuser"
,
"oranpassword"
)
nc
.
edit_config
([
"{{ CreateProcessingEle_template }}"
,
"{{ cu_inactive_config_template }}"
,
"{{ cu_config_template }}"
])
break
except
Exception
as
e
:
nc
.
logger
.
debug
(
'Got exception, waiting 10 seconds before reconnecting...'
)
nc
.
logger
.
debug
(
e
)
time
.
sleep
(
10
)
finally
:
nc
.
close
()
software/ors-amarisoft/ru/lopcomm/cu_config.jinja2.xml
deleted
100644 → 0
View file @
c3244027
<xc:config
xmlns:xc=
"urn:ietf:params:xml:ns:netconf:base:1.0"
>
<user-plane-configuration
xc:operation=
"replace"
xmlns=
"urn:o-ran:uplane-conf-option8:1.0"
>
<!-- TX path: eaxcid → TxEndpoint
↘
mod → static TxEndpoint → TxArray
↗
TxCarrier
(static TxEndpoint, TxArray and their association are defined by RU itself)
-->
{%- set TxCarrier = 'TXA0CC00' %}
{%- for ant in range(ru.n_antenna_dl) %}
{%- set port = ant // 2 %}
{%- set chan = ant % 2 %}
{%- set txep = 'TXA0P%02dC%02d' % (port, chan) %}
<!-- TxAntenna{{ ant }} -->
<tx-endpoints>
<name>
{{ txep }}
</name>
<e-axcid>
<o-du-port-bitmask>
61440
</o-du-port-bitmask>
<band-sector-bitmask>
3968
</band-sector-bitmask>
<ccid-bitmask>
112
</ccid-bitmask>
<ru-port-bitmask>
15
</ru-port-bitmask>
<eaxc-id>
{{ ant }}
</eaxc-id>
</e-axcid>
</tx-endpoints>
<tx-links>
<name>
{{ txep }}
</name>
<processing-element>
PE0
</processing-element>
<tx-array-carrier>
{{ TxCarrier }}
</tx-array-carrier>
<tx-endpoint>
{{ txep }}
</tx-endpoint>
</tx-links>
{%- endfor %}
<!--
RX path: eaxcid ← RxEndpoint
(data ∪ prach)
↖
demod ← static RxEndpoint ← RxArray
↗
RxCarrier
(static RxEndpoint, RxArray and their association are defined by RU itself)
-->
{%- set RxCarrier = 'RXA0CC00' %}
{%- for ant in range(ru.n_antenna_ul) %}
{%- set port = ant // 2 %}
{%- set chan = ant % 2 %}
{%- set rxep = 'RXA0P%02dC%02d' % (port, chan) %}
{%- set prachep = 'PRACH0P%02dC%02d' % (port, chan) %}
<!-- RxAntenna{{ ant }} -->
<rx-endpoints>
<name>
{{ rxep }}
</name>
<e-axcid>
<o-du-port-bitmask>
61440
</o-du-port-bitmask>
<band-sector-bitmask>
3968
</band-sector-bitmask>
<ccid-bitmask>
112
</ccid-bitmask>
<ru-port-bitmask>
15
</ru-port-bitmask>
<eaxc-id>
{{ ant }}
</eaxc-id>
</e-axcid>
</rx-endpoints>
<rx-endpoints>
<name>
{{ prachep }}
</name>
<e-axcid>
<o-du-port-bitmask>
61440
</o-du-port-bitmask>
<band-sector-bitmask>
3968
</band-sector-bitmask>
<ccid-bitmask>
112
</ccid-bitmask>
<ru-port-bitmask>
15
</ru-port-bitmask>
<eaxc-id>
{{ 16*chan + 8 + port }}
</eaxc-id>
</e-axcid>
</rx-endpoints>
<rx-links>
<name>
{{ rxep }}
</name>
<processing-element>
PE0
</processing-element>
<rx-array-carrier>
{{ RxCarrier }}
</rx-array-carrier>
<rx-endpoint>
{{ rxep }}
</rx-endpoint>
</rx-links>
<rx-links>
<name>
{{ prachep }}
</name>
<processing-element>
PE0
</processing-element>
<rx-array-carrier>
{{ RxCarrier }}
</rx-array-carrier>
<rx-endpoint>
{{ prachep }}
</rx-endpoint>
</rx-links>
{%- endfor %}
<!-- TX/RX carriers -->
<!-- TODO support multiple cells over 1 RU -->
{%- if cell.cell_type == 'lte' %}
{%- set dl_arfcn = cell.dl_earfcn %}
{%- set ul_arfcn = cell.ul_earfcn %}
{%- set dl_freq = int(xearfcn_module.frequency(dl_arfcn) * 1e6) %}
{%- set ul_freq = int(xearfcn_module.frequency(ul_arfcn) * 1e6) %}
{%- elif cell.cell_type == 'nr' %}
{%- set dl_arfcn = cell.dl_nr_arfcn %}
{%- set ul_arfcn = cell.ul_nr_arfcn %}
{%- set dl_freq = int(xnrarfcn_module.frequency(dl_arfcn) * 1e6) %}
{%- set ul_freq = int(xnrarfcn_module.frequency(ul_arfcn) * 1e6) %}
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
{%- set bw = int(cell.bandwidth * 1e6) %}
<tx-array-carriers>
<name>
{{ TxCarrier }}
</name>
<absolute-frequency-center>
{{ dl_arfcn }}
</absolute-frequency-center>
<center-of-channel-bandwidth>
{{ dl_freq }}
</center-of-channel-bandwidth>
<channel-bandwidth>
{{ bw }}
</channel-bandwidth>
<active>
{{ ru.txrx_active }}
</active>
<rw-type>
{{ cell.cell_type | upper }}
</rw-type>
<rw-duplex-scheme>
{{ cell.rf_mode | upper }}
</rw-duplex-scheme>
<gain>
{{ ru.tx_gain }}
</gain>
<downlink-radio-frame-offset>
0
</downlink-radio-frame-offset>
<downlink-sfn-offset>
0
</downlink-sfn-offset>
</tx-array-carriers>
<rx-array-carriers>
<name>
{{ RxCarrier }}
</name>
<absolute-frequency-center>
{{ ul_arfcn }}
</absolute-frequency-center>
<center-of-channel-bandwidth>
{{ ul_freq }}
</center-of-channel-bandwidth>
<channel-bandwidth>
{{ bw }}
</channel-bandwidth>
<active>
{{ ru.txrx_active }}
</active>
<downlink-radio-frame-offset>
0
</downlink-radio-frame-offset>
<downlink-sfn-offset>
0
</downlink-sfn-offset>
<!-- <gain>{{ ru.rx_gain }}</gain> -->
<!-- TODO(lu.xu): clarify with Lopcomm regaring rx gain -->
<gain-correction>
0.0
</gain-correction>
<n-ta-offset>
0
</n-ta-offset>
</rx-array-carriers>
</user-plane-configuration>
</xc:config>
software/ors-amarisoft/ru/lopcomm/input-schema.json
deleted
100644 → 0
View file @
c3244027
{
"$schema"
:
"https://json-schema.org/draft/2020-12/schema"
,
"title"
:
"Lopcomm ORAN"
,
"type"
:
"object"
,
"required"
:
[
"ru_type"
,
"ru_link_type"
,
"n_antenna_dl"
,
"n_antenna_ul"
,
"tx_gain"
,
"rx_gain"
,
"cpri_link"
,
"mac_addr"
],
"properties"
:
{
"$ref"
:
"../../ru/common.json#/properties"
,
"ru_type"
:
{
"$ref"
:
"#/properties/ru_type"
,
"const"
:
"lopcomm"
},
"ru_link_type"
:
{
"$ref"
:
"#/properties/ru_link_type"
,
"const"
:
"cpri"
},
"n_antenna_dl"
:
{
"$ref"
:
"#/properties/n_antenna_dl"
,
"default"
:
2
},
"n_antenna_ul"
:
{
"$ref"
:
"#/properties/n_antenna_ul"
,
"default"
:
2
},
"cpri_link"
:
{
"$ref"
:
"#/properties/cpri_link"
,
"properties"
:
{
"$ref"
:
"#/properties/cpri_link/properties"
,
"mapping"
:
{
"$ref"
:
"#/properties/cpri_link/properties/mapping"
,
"const"
:
"hw"
,
"enum"
:
[
"hw"
]
},
"rx_delay"
:
{
"$ref"
:
"#/properties/cpri_link/properties/rx_delay"
,
"default"
:
25.11
},
"tx_delay"
:
{
"$ref"
:
"#/properties/cpri_link/properties/tx_delay"
,
"default"
:
14.71
},
"tx_dbm"
:
{
"$ref"
:
"#/properties/cpri_link/properties/tx_dbm"
,
"default"
:
63
}
}
},
"reset_schedule"
:
{
"title"
:
"Cron schedule for RRH reset"
,
"description"
:
"Refer https://crontab.guru/ to make a reset schedule for RRH, for example, '0 1 * * *' means the RRH will reset every day at 1 am"
,
"type"
:
"string"
}
}
}
software/ors-amarisoft/ru/lopcomm/libinstance.jinja2.cfg
deleted
100644 → 0
View file @
c3244027
This diff is collapsed.
Click to expand it.
software/ors-amarisoft/ru/lopcomm/ncclient_common.py
deleted
100644 → 0
View file @
c3244027
This diff is collapsed.
Click to expand it.
software/ors-amarisoft/ru/lopcomm/reset-info.jinja2.py
deleted
100644 → 0
View file @
c3244027
#!{{ python_path }}
import
paramiko
import
logging
from
logging.handlers
import
RotatingFileHandler
def
get_uptime
(
hostname
,
username
,
password
):
client
=
paramiko
.
SSHClient
()
client
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
try
:
client
.
connect
(
hostname
,
username
=
username
,
password
=
password
)
stdin
,
stdout
,
stderr
=
client
.
exec_command
(
'uptime'
)
uptime_output
=
stdout
.
read
().
decode
()
return
uptime_output
except
Exception
as
e
:
logger
.
info
(
f"Error:
{
e
}
"
)
finally
:
client
.
close
()
# Usage
hostname
=
"{{ netaddr.IPAddress(vtap.gateway) }}"
username
=
"oranuser"
password
=
"oranpassword"
# Initialize logger
log_file
=
"{{ log_file }}"
logger
=
logging
.
getLogger
(
'logger'
)
logger
.
setLevel
(
logging
.
INFO
)
handler
=
RotatingFileHandler
(
log_file
,
maxBytes
=
30000
,
backupCount
=
2
)
formatter
=
logging
.
Formatter
(
'%(asctime)s - %(levelname)s - %(message)s'
)
handler
.
setFormatter
(
formatter
)
logger
.
addHandler
(
handler
)
if
{{
testing
}}:
pass
else
:
rrh_uptime
=
get_uptime
(
hostname
,
username
,
password
)
logger
.
info
(
f"Uptime from RRH:
{
rrh_uptime
}
"
)
software/ors-amarisoft/ru/lopcomm/reset.jinja2.py
deleted
100644 → 0
View file @
c3244027
#!{{ python_path }}
import
time
import
sys
sys
.
path
.
append
({{
repr
(
buildout_directory_path
)
}})
from
ncclient_common
import
LopcommNetconfClient
if
__name__
==
'__main__'
:
nc
=
LopcommNetconfClient
(
log_file
=
"{{ log_file }}"
)
try
:
nc
.
connect
(
"{{ netaddr.IPAddress(vtap.gateway) }}"
,
830
,
"oranuser"
,
"oranpassword"
)
nc
.
reset_device
()
nc
.
logger
.
info
(
"Device reset successful."
)
except
Exception
as
e
:
nc
.
logger
.
debug
(
'Got exception while resetting...'
)
nc
.
logger
.
debug
(
e
)
finally
:
nc
.
close
()
software/ors-amarisoft/ru/lopcomm/software.jinja2.py
deleted
100644 → 0
View file @
c3244027
#!{{ python_path }}
import
time
import
json
import
xmltodict
import
sys
import
re
import
os
sys
.
path
.
append
({{
repr
(
buildout_directory_path
)
}})
from
ncclient_common
import
LopcommNetconfClient
if
__name__
==
'__main__'
:
nc
=
LopcommNetconfClient
(
log_file
=
"{{ log_file }}"
,
software_reply_json_log_file
=
"{{ software_reply_json_log_file }}"
)
while
True
:
try
:
firmware_check_file
=
'{{ is_firmware_updated }}'
nc
.
connect
(
"{{ netaddr.IPAddress(vtap.gateway) }}"
,
830
,
"oranuser"
,
"oranpassword"
)
# Fetch software inventory
inventory_vars
=
nc
.
get_inventory
()
nonrunning_slot_name
=
inventory_vars
[
"nonrunning_slot_name"
]
running_slot_name
=
inventory_vars
[
"running_slot_name"
]
active_nonrunning_slot_name
=
inventory_vars
[
"active_nonrunning_slot_name"
]
nonrunning_slot_name_build_version
=
inventory_vars
[
"nonrunning_slot_name_build_version"
]
running_slot_name_build_version
=
inventory_vars
[
"running_slot_name_build_version"
]
if
running_slot_name
and
nonrunning_slot_name
:
if
running_slot_name
:
nc
.
logger
.
info
(
"One slot is running and one is non-running. Proceeding..."
)
if
running_slot_name_build_version
in
"{{firmware_name}}"
:
if
not
os
.
path
.
exists
(
firmware_check_file
):
open
(
firmware_check_file
,
"w"
).
write
(
'True'
)
nc
.
logger
.
info
(
"Running slot's build-version %s is already updated. Skipping install."
%
running_slot_name_build_version
)
else
:
if
os
.
path
.
exists
(
firmware_check_file
):
os
.
remove
(
firmware_check_file
)
nc
.
logger
.
info
(
"Current build version: %s"
%
running_slot_name_build_version
)
user_authorized_key
=
"""{{ slapparameter_dict.get('user-authorized-key', '') }}"""
match
=
re
.
match
(
r'ssh-rsa ([^\
s]+)
', user_authorized_key)
if match:
extracted_key = match.group(1)
else:
nc.logger.info("No valid key found in user authorized key.")
download_rpc_xml = f"""
<software-download xmlns="urn:o-ran:software-management:1.0">
<remote-file-path>{{remote_file_path}}</remote-file-path>
<server>
<keys>
<algorithm xmlns:ct="urn:ietf:params:xml:ns:yang:ietf-crypto-types">1024</algorithm>
<public-key>{extracted_key}</public-key>
</keys>
</server>
</software-download>
"""
download_reply_xml = nc.custom_rpc_request(download_rpc_xml)
nc.logger.info("Downloading software...")
time.sleep(60)
if download_reply_xml:
nc.logger.info("Download proceed.")
download_data = xmltodict.parse(download_reply_xml)
nc.software_reply_json_logger.info('', extra={'
data
': json.dumps(download_data)})
install_rpc_xml = f"""
<software-install xmlns="urn:o-ran:software-management:1.0">
<slot-name>{nonrunning_slot_name}</slot-name>
<file-names>{{firmware_name}}</file-names>
</software-install>
"""
install_reply_xml = nc.custom_rpc_request(install_rpc_xml)
nc.logger.info("Installing software...")
time.sleep(60)
if install_reply_xml:
nc.logger.info("Installation proceed.")
install_data = xmltodict.parse(install_reply_xml)
nc.software_reply_json_logger.info('', extra={'
data
': json.dumps(install_data)})
if nonrunning_slot_name_build_version in "{{firmware_name}}":
activate_rpc_xml = f"""
<software-activate xmlns="urn:o-ran:software-management:1.0">
<slot-name>{nonrunning_slot_name}</slot-name>
</software-activate>
"""
activate_reply_xml = nc.custom_rpc_request(activate_rpc_xml)
nc.logger.info("Activating software...")
time.sleep(60)
if activate_reply_xml:
nc.logger.info("Activation proceed.")
activate_data = xmltodict.parse(activate_reply_xml)
nc.software_reply_json_logger.info('', extra={'
data
': json.dumps(activate_data)})
nc.get_inventory()
if nonrunning_slot_name_build_version in "{{firmware_name}}" and active_nonrunning_slot_name:
nc.logger.info("Active non-running slot has the updated build version. Resetting device.")
nc.reset_device()
break
except Exception as e:
nc.logger.debug('
Got
exception
,
waiting
10
seconds
before
reconnecting
...
')
nc.logger.debug(str(e))
time.sleep(10)
finally:
nc.close()
software/ors-amarisoft/ru/lopcomm/stats.jinja2.py
deleted
100644 → 0
View file @
c3244027
#!{{ python_path }}
import
time
import
sys
import
os
import
threading
sys
.
path
.
append
({{
repr
(
buildout_directory_path
)
}})
from
ncclient_common
import
LopcommNetconfClient
# Shared variable to indicate error occurred
error_occurred
=
False
lock
=
threading
.
Lock
()
def
get_notification_continuously
(
nc
):
global
error_occurred
try
:
while
not
error_occurred
:
nc
.
get_notification
()
pass
except
Exception
as
e
:
with
lock
:
error_occurred
=
True
nc
.
logger
.
error
(
f'Error in get_notification_continuously:
{
e
}
'
)
# supervision watchdog keeps on
def
run_supervision_reset_continuously
(
nc
):
global
error_occurred
netconf_check_file
=
'{{ is_netconf_connected }}'
interval
=
60
margin
=
10
try
:
while
not
error_occurred
:
t0
=
time
.
time
()
replied
=
nc
.
supervision_reset
(
interval
,
margin
)
if
replied
:
with
open
(
netconf_check_file
,
"w"
)
as
f
:
f
.
write
(
''
)
elif
os
.
path
.
exists
(
netconf_check_file
):
os
.
remove
(
netconf_check_file
)
t1
=
time
.
time
()
time
.
sleep
(
interval
-
(
t1
-
t0
))
except
Exception
as
e
:
with
lock
:
error_occurred
=
True
nc
.
logger
.
error
(
f'Error in run_supervision_reset_continuously:
{
e
}
'
)
if
__name__
==
'__main__'
:
nc
=
LopcommNetconfClient
(
log_file
=
"{{ log_file }}"
,
json_log_file
=
"{{ json_log_file }}"
,
cfg_json_log_file
=
"{{ cfg_json_log_file }}"
,
supervision_json_log_file
=
"{{ supervision_json_log_file }}"
,
ncsession_json_log_file
=
"{{ ncsession_json_log_file }}"
,
software_json_log_file
=
"{{ software_json_log_file }}"
,
supervision_reply_json_log_file
=
"{{ supervision_reply_json_log_file }}"
)
threads
=
[]
try
:
nc
.
connect
(
"{{ netaddr.IPAddress(vtap.gateway) }}"
,
830
,
"oranuser"
,
"oranpassword"
)
nc
.
subscribe
()
notification_thread
=
threading
.
Thread
(
target
=
get_notification_continuously
,
args
=
(
nc
,))
supervision_thread
=
threading
.
Thread
(
target
=
run_supervision_reset_continuously
,
args
=
(
nc
,))
threads
.
append
(
notification_thread
)
threads
.
append
(
supervision_thread
)
for
thread
in
threads
:
thread
.
start
()
for
thread
in
threads
:
thread
.
join
()
except
Exception
as
e
:
nc
.
logger
.
debug
(
'Got exception, waiting 10 seconds before reconnecting...'
)
nc
.
logger
.
debug
(
e
)
time
.
sleep
(
10
)
finally
:
nc
.
close
()
software/ors-amarisoft/slaplte.jinja2
View file @
7a31af8e
...
...
@@ -34,17 +34,6 @@
'tx_dbm': 0,
},
'ru/lopcomm': {
'n_antenna_dl': 2,
'n_antenna_ul': 2,
},
'ru/lopcomm/cpri_link': {
'mapping': 'hw',
'rx_delay': 25.11,
'tx_delay': 14.71,
'tx_dbm': 63,
},
'ru/sunwave': {
'n_antenna_dl': 2,
'n_antenna_ul': 1,
...
...
software/ors-amarisoft/test/test.py
View file @
7a31af8e
...
...
@@ -502,171 +502,6 @@ class SDR4:
))
# Lopcomm4 is mixin to verify Lopcomm driver wrt all LTE/NR x FDD/TDD modes.
class
Lopcomm4
:
@
classmethod
def
RUcfg
(
cls
,
i
):
return
{
'ru_type'
:
'lopcomm'
,
'ru_link_type'
:
'cpri'
,
'cpri_link'
:
{
'sdr_dev'
:
0
,
'sfp_port'
:
i
,
'mult'
:
4
,
'mapping'
:
'hw'
,
'rx_delay'
:
40
+
i
,
'tx_delay'
:
50
+
i
,
'tx_dbm'
:
60
+
i
},
'mac_addr'
:
'00:0A:45:00:00:%02x'
%
i
,
}
# radio units configuration in enb.cfg
def
test_rf_cfg_ru
(
t
):
assertMatch
(
t
,
t
.
rf_cfg
[
'rf_driver'
],
dict
(
name
=
'sdr'
,
args
=
'dev0=/dev/sdr0@1,dev1=/dev/sdr0@2,dev2=/dev/sdr0@3,dev3=/dev/sdr0@4'
,
cpri_mapping
=
'hw,hw,hw,hw'
,
cpri_mult
=
'4,4,4,4'
,
cpri_rx_delay
=
'41,42,43,44'
,
cpri_tx_delay
=
'51,52,53,54'
,
cpri_tx_dbm
=
'61,62,63,64'
,
))
# RU configuration in cu_config.xml
def
test_ru_cu_config_xml
(
t
):
def
uctx
(
rf_mode
,
cell_type
,
dl_arfcn
,
ul_arfcn
,
bw
,
dl_freq
,
ul_freq
,
tx_gain
,
rx_gain
):
return
{
'tx-array-carriers'
:
{
'rw-duplex-scheme'
:
rf_mode
,
'rw-type'
:
cell_type
,
'absolute-frequency-center'
:
'%d'
%
dl_arfcn
,
'center-of-channel-bandwidth'
:
'%d'
%
dl_freq
,
'channel-bandwidth'
:
'%d'
%
bw
,
'gain'
:
'%d'
%
tx_gain
,
'active'
:
'ACTIVE'
,
},
'rx-array-carriers'
:
{
'absolute-frequency-center'
:
'%d'
%
ul_arfcn
,
'center-of-channel-bandwidth'
:
'%d'
%
ul_freq
,
'channel-bandwidth'
:
'%d'
%
bw
,
# XXX no rx_gain
'active'
:
'ACTIVE'
,
},
}
_
=
t
.
_test_ru_cu_config_xml
# rf_mode ctype dl_arfcn ul_arfcn bw dl_freq ul_freq txg rxg
_
(
1
,
uctx
(
'FDD'
,
'LTE'
,
100
,
18100
,
5000000
,
2120000000
,
1930000000
,
11
,
21
))
_
(
2
,
uctx
(
'TDD'
,
'LTE'
,
40200
,
40200
,
10000000
,
2551000000
,
2551000000
,
12
,
22
))
_
(
3
,
uctx
(
'FDD'
,
'NR'
,
300300
,
290700
,
15000000
,
1501500000
,
1453500000
,
13
,
23
))
_
(
4
,
uctx
(
'TDD'
,
'NR'
,
470400
,
470400
,
20000000
,
2352000000
,
2352000000
,
14
,
24
))
def
_test_ru_cu_config_xml
(
t
,
i
,
uctx
):
cu_xml
=
t
.
ipath
(
'etc/%s'
%
xbuildout
.
encode
(
'%s-cu_config.xml'
%
t
.
ref
(
'RU%d'
%
i
)))
with
open
(
cu_xml
,
'r'
)
as
f
:
cu
=
f
.
read
()
cu
=
xmltodict
.
parse
(
cu
)
assertMatch
(
t
,
cu
,
{
'xc:config'
:
{
'user-plane-configuration'
:
{
'tx-endpoints'
:
[
{
'name'
:
'TXA0P00C00'
,
'e-axcid'
:
{
'eaxc-id'
:
'0'
}},
{
'name'
:
'TXA0P00C01'
,
'e-axcid'
:
{
'eaxc-id'
:
'1'
}},
{
'name'
:
'TXA0P01C00'
,
'e-axcid'
:
{
'eaxc-id'
:
'2'
}},
{
'name'
:
'TXA0P01C01'
,
'e-axcid'
:
{
'eaxc-id'
:
'3'
}},
],
'tx-links'
:
[
{
'name'
:
'TXA0P00C00'
,
'tx-endpoint'
:
'TXA0P00C00'
},
{
'name'
:
'TXA0P00C01'
,
'tx-endpoint'
:
'TXA0P00C01'
},
{
'name'
:
'TXA0P01C00'
,
'tx-endpoint'
:
'TXA0P01C00'
},
{
'name'
:
'TXA0P01C01'
,
'tx-endpoint'
:
'TXA0P01C01'
},
],
'rx-endpoints'
:
[
{
'name'
:
'RXA0P00C00'
,
'e-axcid'
:
{
'eaxc-id'
:
'0'
}},
{
'name'
:
'PRACH0P00C00'
,
'e-axcid'
:
{
'eaxc-id'
:
'8'
}},
{
'name'
:
'RXA0P00C01'
,
'e-axcid'
:
{
'eaxc-id'
:
'1'
}},
{
'name'
:
'PRACH0P00C01'
,
'e-axcid'
:
{
'eaxc-id'
:
'24'
}},
],
'rx-links'
:
[
{
'name'
:
'RXA0P00C00'
,
'rx-endpoint'
:
'RXA0P00C00'
},
{
'name'
:
'PRACH0P00C00'
,
'rx-endpoint'
:
'PRACH0P00C00'
},
{
'name'
:
'RXA0P00C01'
,
'rx-endpoint'
:
'RXA0P00C01'
},
{
'name'
:
'PRACH0P00C01'
,
'rx-endpoint'
:
'PRACH0P00C01'
},
],
}
|
uctx
}
})
# RU configuration in cu_inactive_config.xml
def
test_ru_cu_inactive_config_xml
(
t
):
def
uctx
(
rf_mode
,
cell_type
,
dl_arfcn
,
ul_arfcn
,
bw
,
dl_freq
,
ul_freq
,
tx_gain
,
rx_gain
):
return
{
'tx-array-carriers'
:
{
'rw-duplex-scheme'
:
rf_mode
,
'rw-type'
:
cell_type
,
'absolute-frequency-center'
:
'%d'
%
dl_arfcn
,
'center-of-channel-bandwidth'
:
'%d'
%
dl_freq
,
'channel-bandwidth'
:
'%d'
%
bw
,
'gain'
:
'%d'
%
tx_gain
,
'active'
:
'INACTIVE'
,
},
'rx-array-carriers'
:
{
'absolute-frequency-center'
:
'%d'
%
ul_arfcn
,
'center-of-channel-bandwidth'
:
'%d'
%
ul_freq
,
'channel-bandwidth'
:
'%d'
%
bw
,
# XXX no rx_gain
'active'
:
'INACTIVE'
,
},
}
_
=
t
.
_test_ru_cu_inactive_config_xml
# rf_mode ctype dl_arfcn ul_arfcn bw dl_freq ul_freq txg rxg
_
(
1
,
uctx
(
'FDD'
,
'LTE'
,
100
,
18100
,
5000000
,
2120000000
,
1930000000
,
11
,
21
))
_
(
2
,
uctx
(
'TDD'
,
'LTE'
,
40200
,
40200
,
10000000
,
2551000000
,
2551000000
,
12
,
22
))
_
(
3
,
uctx
(
'FDD'
,
'NR'
,
300300
,
290700
,
15000000
,
1501500000
,
1453500000
,
13
,
23
))
_
(
4
,
uctx
(
'TDD'
,
'NR'
,
470400
,
470400
,
20000000
,
2352000000
,
2352000000
,
14
,
24
))
def
_test_ru_cu_inactive_config_xml
(
t
,
i
,
uctx
):
cu_xml
=
t
.
ipath
(
'etc/%s'
%
xbuildout
.
encode
(
'%s-cu_inactive_config.xml'
%
t
.
ref
(
'RU%d'
%
i
)))
with
open
(
cu_xml
,
'r'
)
as
f
:
cu
=
f
.
read
()
cu
=
xmltodict
.
parse
(
cu
)
assertMatch
(
t
,
cu
,
{
'xc:config'
:
{
'user-plane-configuration'
:
{
'tx-endpoints'
:
[
{
'name'
:
'TXA0P00C00'
,
'e-axcid'
:
{
'eaxc-id'
:
'0'
}},
{
'name'
:
'TXA0P00C01'
,
'e-axcid'
:
{
'eaxc-id'
:
'1'
}},
{
'name'
:
'TXA0P01C00'
,
'e-axcid'
:
{
'eaxc-id'
:
'2'
}},
{
'name'
:
'TXA0P01C01'
,
'e-axcid'
:
{
'eaxc-id'
:
'3'
}},
],
'tx-links'
:
[
{
'name'
:
'TXA0P00C00'
,
'tx-endpoint'
:
'TXA0P00C00'
},
{
'name'
:
'TXA0P00C01'
,
'tx-endpoint'
:
'TXA0P00C01'
},
{
'name'
:
'TXA0P01C00'
,
'tx-endpoint'
:
'TXA0P01C00'
},
{
'name'
:
'TXA0P01C01'
,
'tx-endpoint'
:
'TXA0P01C01'
},
],
'rx-endpoints'
:
[
{
'name'
:
'RXA0P00C00'
,
'e-axcid'
:
{
'eaxc-id'
:
'0'
}},
{
'name'
:
'PRACH0P00C00'
,
'e-axcid'
:
{
'eaxc-id'
:
'8'
}},
{
'name'
:
'RXA0P00C01'
,
'e-axcid'
:
{
'eaxc-id'
:
'1'
}},
{
'name'
:
'PRACH0P00C01'
,
'e-axcid'
:
{
'eaxc-id'
:
'24'
}},
],
'rx-links'
:
[
{
'name'
:
'RXA0P00C00'
,
'rx-endpoint'
:
'RXA0P00C00'
},
{
'name'
:
'PRACH0P00C00'
,
'rx-endpoint'
:
'PRACH0P00C00'
},
{
'name'
:
'RXA0P00C01'
,
'rx-endpoint'
:
'RXA0P00C01'
},
{
'name'
:
'PRACH0P00C01'
,
'rx-endpoint'
:
'PRACH0P00C01'
},
],
}
|
uctx
}
})
# Sunwave4 is mixin to verify Sunwave driver wrt all LTE/NR x FDD/TDD modes.
class
Sunwave4
:
@
classmethod
...
...
@@ -699,35 +534,35 @@ class Sunwave4:
))
# RUMultiType4 is mixin to verify that different RU types can be used at the same time.
class
RUMultiType4
:
# ENB does not support mixing SDR + CPRI - verify only with CPRI-based units
# see https://support.amarisoft.com/issues/26021 for details
@
classmethod
def
RUcfg
(
cls
,
i
):
assert
1
<=
i
<=
4
,
i
if
i
in
(
1
,
2
):
return
Lopcomm4
.
RUcfg
(
i
)
else
:
return
Sunwave4
.
RUcfg
(
i
)
# radio units configuration in enb.cfg
def
test_rf_cfg_ru
(
t
):
assertMatch
(
t
,
t
.
rf_cfg
[
'rf_driver'
],
dict
(
name
=
'sdr'
,
args
=
'dev0=/dev/sdr0@1,dev1=/dev/sdr0@2,dev2=/dev/sdr1@3,dev3=/dev/sdr1@4'
,
cpri_mapping
=
'hw,hw,bf1,bf1'
,
cpri_mult
=
'4,4,5,5'
,
cpri_rx_delay
=
'41,42,143,144'
,
cpri_tx_delay
=
'51,52,153,154'
,
cpri_tx_dbm
=
'61,62,163,164'
,
))
# Due to only one type of RU being supported in the SR, the test is currently not applicable.
#class RUMultiType4:
# # ENB does not support mixing SDR + CPRI - verify only with CPRI-based units
# # see https://support.amarisoft.com/issues/26021 for details
# @classmethod
# def RUcfg(cls, i):
# assert 1 <= i <= 4, i
# if i in (1,2):
# return SDR4.RUcfg(i)
# else:
# return Sunwave4.RUcfg(i)
#
# # radio units configuration in enb.cfg
# def test_rf_cfg_ru(t):
# assertMatch(t, t.rf_cfg['rf_driver'], dict(
# name='sdr',
# args='dev0=/dev/sdr0@1,dev1=/dev/sdr0@2,dev2=/dev/sdr1@3,dev3=/dev/sdr1@4',
# cpri_mapping='hw,hw,bf1,bf1',
# cpri_mult='4,4,5,5',
# cpri_rx_delay='41,42,143,144',
# cpri_tx_delay='51,52,153,154',
# cpri_tx_dbm='61,62,163,164',
# ))
# instantiate eNB tests
class
TestENB_SDR4
(
ENBTestCase4
,
SDR4
):
pass
class
TestENB_Lopcomm4
(
ENBTestCase4
,
Lopcomm4
):
pass
class
TestENB_Sunwave4
(
ENBTestCase4
,
Sunwave4
):
pass
class
TestENB_RUMultiType4
(
ENBTestCase4
,
RUMultiType4
):
pass
#
class TestENB_RUMultiType4(ENBTestCase4, RUMultiType4): pass
# ---- UEsim ----
...
...
@@ -844,9 +679,8 @@ class UEsimTestCase4(RFTestCase4):
# instantiate UEsim tests
class
TestUEsim_SDR4
(
UEsimTestCase4
,
SDR4
):
pass
class
TestUEsim_Lopcomm4
(
UEsimTestCase4
,
Lopcomm4
):
pass
class
TestUEsim_Sunwave4
(
UEsimTestCase4
,
Sunwave4
):
pass
class
TestUEsim_RUMultiType4
(
UEsimTestCase4
,
RUMultiType4
):
pass
#
class TestUEsim_RUMultiType4(UEsimTestCase4, RUMultiType4): pass
# ---- misc ----
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment