dapps 0.0.4__tar.gz → 0.0.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dapps-0.0.6/CONTRIBUTING.md +95 -0
- {dapps-0.0.4 → dapps-0.0.6}/PKG-INFO +112 -25
- dapps-0.0.6/README.md +156 -0
- dapps-0.0.6/VERSION +1 -0
- dapps-0.0.6/docs/dapp_uml.txt +210 -0
- dapps-0.0.6/examples/nvidia_dapp.py +43 -0
- dapps-0.0.6/examples/simple_dapp.py +123 -0
- {dapps-0.0.4 → dapps-0.0.6}/examples/spectrum_dapp.py +45 -14
- {dapps-0.0.4 → dapps-0.0.6}/pyproject.toml +9 -4
- dapps-0.0.6/src/dapp/dapp.py +186 -0
- dapps-0.0.6/src/e3interface/defs/e3.asn +105 -0
- dapps-0.0.6/src/e3interface/defs/e3.json +494 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/e3interface/e3_connector.py +40 -24
- dapps-0.0.6/src/e3interface/e3_encoder.py +376 -0
- dapps-0.0.6/src/e3interface/e3_interface.py +467 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/e3interface/e3_logging.py +4 -5
- dapps-0.0.6/src/iq_saver/__init__.py +3 -0
- dapps-0.0.6/src/iq_saver/iq_saver.py +424 -0
- dapps-0.0.6/src/nvidia/defs/e3sm_nvidia.asn +48 -0
- dapps-0.0.6/src/nvidia/defs/e3sm_nvidia.json +40 -0
- dapps-0.0.6/src/nvidia/nvidia_dapp.py +71 -0
- dapps-0.0.6/src/simple/__init__.py +4 -0
- dapps-0.0.6/src/simple/defs/e3sm_simple.asn +54 -0
- dapps-0.0.6/src/simple/simple_dapp.py +239 -0
- dapps-0.0.6/src/spectrum/defs/e3sm_spectrum.asn +76 -0
- dapps-0.0.6/src/spectrum/defs/e3sm_spectrum.json +137 -0
- dapps-0.0.6/src/spectrum/spectrum_dapp.py +542 -0
- dapps-0.0.6/src/visualization/__init__.py +4 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/visualization/dashboard.py +5 -3
- dapps-0.0.6/tests/test_iq_saver.py +432 -0
- dapps-0.0.6/tools/README.md +117 -0
- dapps-0.0.6/tools/asntojson.py +335 -0
- dapps-0.0.6/tools/generate_sm.sh +1125 -0
- dapps-0.0.6/tools/read_recording.py +50 -0
- dapps-0.0.4/README.md +0 -70
- dapps-0.0.4/VERSION +0 -1
- dapps-0.0.4/docker/Dockerfile +0 -65
- dapps-0.0.4/docker/build.sh +0 -7
- dapps-0.0.4/docs/dapp_uml.txt +0 -128
- dapps-0.0.4/e3protocol/README.md +0 -10
- dapps-0.0.4/e3protocol/build_asn.sh +0 -27
- dapps-0.0.4/e3protocol/client/client.c +0 -164
- dapps-0.0.4/e3protocol/dump_packets.sh +0 -3
- dapps-0.0.4/e3protocol/server/server.py +0 -70
- dapps-0.0.4/e3protocol/wrapper/e3.c +0 -168
- dapps-0.0.4/e3protocol/wrapper/e3.h +0 -11
- dapps-0.0.4/src/dapp/dapp.py +0 -66
- dapps-0.0.4/src/e3interface/defs/e3.asn +0 -27
- dapps-0.0.4/src/e3interface/e3_interface.py +0 -187
- dapps-0.0.4/src/spectrum/spectrum_dapp.py +0 -170
- {dapps-0.0.4 → dapps-0.0.6}/.github/workflows/mirror.yml +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/.github/workflows/tag-and-release.yml +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/.gitignore +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/LICENSE +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/MANIFEST.in +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/docs/gui_uml.txt +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/dapp/__init__.py +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/e3interface/__init__.py +0 -0
- {dapps-0.0.4/src/spectrum → dapps-0.0.6/src/nvidia}/__init__.py +0 -0
- {dapps-0.0.4/src/visualization → dapps-0.0.6/src/spectrum}/__init__.py +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/visualization/energy.py +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/visualization/grafana.py +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/visualization/influx.py +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/visualization/iq.py +0 -0
- {dapps-0.0.4 → dapps-0.0.6}/src/visualization/templates/index.html +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thank you for considering contributing to this project! Please follow these guidelines to help us maintain a welcoming and productive environment.
|
|
4
|
+
When contributing to this repository, please first discuss the change you wish to make via issue,
|
|
5
|
+
email, or any other method with the original authors of this work.
|
|
6
|
+
|
|
7
|
+
Please note we have a code of conduct, please follow it in all your interactions with the project.
|
|
8
|
+
|
|
9
|
+
## Pull Request Process
|
|
10
|
+
|
|
11
|
+
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
|
|
12
|
+
build.
|
|
13
|
+
2. Update the README.md with details of changes to the interface, this includes new environment
|
|
14
|
+
variables, exposed ports, useful file locations and container parameters.
|
|
15
|
+
3. Increase the version numbers in any examples files and the README.md to the new version that this
|
|
16
|
+
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
|
|
17
|
+
This repository is part of a framework with a counterpart in OpenAirInterface written in C/C++.
|
|
18
|
+
We do not accept major patches that break or reduce compatibility with the twin repository.
|
|
19
|
+
4. Submitted code must have been tested and should work with all the compatible configurations of the framework.
|
|
20
|
+
5. Merging should always be performed via squash commits. Pull Requests must be updated through rebasing, without duplicating commits or altering the original branch history. Merges without prior approval are not allowed, and any accidental violations will result in the deletion of the merge commit.
|
|
21
|
+
|
|
22
|
+
## Code of Conduct
|
|
23
|
+
|
|
24
|
+
### Our Pledge
|
|
25
|
+
|
|
26
|
+
In the interest of fostering an open and welcoming environment, we as
|
|
27
|
+
contributors and maintainers pledge to making participation in our project and
|
|
28
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
|
29
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
30
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
|
31
|
+
orientation.
|
|
32
|
+
|
|
33
|
+
### Our Standards
|
|
34
|
+
|
|
35
|
+
Examples of behavior that contributes to creating a positive environment
|
|
36
|
+
include:
|
|
37
|
+
|
|
38
|
+
* Using welcoming and inclusive language
|
|
39
|
+
* Being respectful of differing viewpoints and experiences
|
|
40
|
+
* Gracefully accepting constructive criticism
|
|
41
|
+
* Focusing on what is best for the community
|
|
42
|
+
* Showing empathy towards other community members
|
|
43
|
+
|
|
44
|
+
Examples of unacceptable behavior by participants include:
|
|
45
|
+
|
|
46
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
47
|
+
advances
|
|
48
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
49
|
+
* Public or private harassment
|
|
50
|
+
* Publishing others' private information, such as a physical or electronic
|
|
51
|
+
address, without explicit permission
|
|
52
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
53
|
+
professional setting
|
|
54
|
+
|
|
55
|
+
### Our Responsibilities
|
|
56
|
+
|
|
57
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
|
58
|
+
behavior and are expected to take appropriate and fair corrective action in
|
|
59
|
+
response to any instances of unacceptable behavior.
|
|
60
|
+
|
|
61
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
|
62
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
63
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
64
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
|
65
|
+
threatening, offensive, or harmful.
|
|
66
|
+
|
|
67
|
+
### Scope
|
|
68
|
+
|
|
69
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
|
70
|
+
when an individual is representing the project or its community. Examples of
|
|
71
|
+
representing a project or community include using an official project e-mail
|
|
72
|
+
address, posting via an official social media account, or acting as an appointed
|
|
73
|
+
representative at an online or offline event. Representation of a project may be
|
|
74
|
+
further defined and clarified by project maintainers.
|
|
75
|
+
|
|
76
|
+
### Enforcement
|
|
77
|
+
|
|
78
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
79
|
+
reported by contacting the project team. All
|
|
80
|
+
complaints will be reviewed and investigated and will result in a response that
|
|
81
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
|
82
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
83
|
+
Further details of specific enforcement policies may be posted separately.
|
|
84
|
+
|
|
85
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
86
|
+
faith may face temporary or permanent repercussions as determined by other
|
|
87
|
+
members of the project's leadership.
|
|
88
|
+
|
|
89
|
+
### Attribution
|
|
90
|
+
|
|
91
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
92
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
|
93
|
+
|
|
94
|
+
[homepage]: http://contributor-covenant.org
|
|
95
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dapps
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.6
|
|
4
4
|
Summary: A library for creating and connecting dApps to Open RAN units.
|
|
5
5
|
Project-URL: Homepage, https://openrangym.com/o-ran-frameworks/dapps
|
|
6
6
|
Project-URL: Package, https://pypi.org/project/dapps/
|
|
7
7
|
Project-URL: Source, https://github.com/wineslab/dApp-library
|
|
8
8
|
Project-URL: Bug Tracker, https://github.com/wineslab/dApp-library/issues
|
|
9
9
|
Author-email: Andrea Lacava <thecave003@gmail.com>
|
|
10
|
+
License-Expression: Apache-2.0
|
|
10
11
|
License-File: LICENSE
|
|
11
12
|
Keywords: 5G,O-RAN,cellular,dApps,networks
|
|
12
13
|
Classifier: Development Status :: 4 - Beta
|
|
13
14
|
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
19
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
21
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.10
|
|
22
21
|
Requires-Dist: asn1tools
|
|
22
|
+
Requires-Dist: jsonschema>=4.18.0
|
|
23
23
|
Requires-Dist: numpy
|
|
24
24
|
Requires-Dist: pyzmq
|
|
25
|
+
Requires-Dist: sigmf
|
|
25
26
|
Requires-Dist: typing-extensions
|
|
26
27
|
Provides-Extra: all
|
|
27
28
|
Requires-Dist: flask; extra == 'all'
|
|
@@ -62,7 +63,7 @@ Clone the repository and install it manually with:
|
|
|
62
63
|
|
|
63
64
|
```
|
|
64
65
|
hatch build
|
|
65
|
-
pip3 install dist/*.tar.gz
|
|
66
|
+
pip3 install "dist/*.tar.gz[all]"
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
### Launch the Spectrum Sharing dApp example
|
|
@@ -74,27 +75,43 @@ python3 examples/spectrum_dapp.py
|
|
|
74
75
|
```
|
|
75
76
|
|
|
76
77
|
This dApp implements a spectrum sharing use case discussed in [our paper](https://doi.org/10.1016/j.comnet.2025.111342) ([here for the archive version](https://arxiv.org/pdf/2501.16502)).
|
|
77
|
-
The dApp parameters can be controlled through the following command-line arguments:
|
|
78
|
-
|
|
79
|
-
- `--link` (str, default: 'zmq', choices: [layer.value for layer in E3LinkLayer]): Specify the link layer to be used
|
|
80
|
-
- `--transport` (str, default: 'ipc', choices: [layer.value for layer in E3TransportLayer]): Specify the transport layer to be used
|
|
81
|
-
- `--save-iqs` (store_true, default: False): Specify if this is data collection run or not. In the first case I/Q samples will be saved
|
|
82
|
-
- `--control` (store_true, default: False): Set whether to perform control of PRB
|
|
83
|
-
- `--noise-floor-threshold` (int, default: None): Set the noise floor threshold for determining the presence of incumbents and for detecting the PRBs affected.
|
|
84
|
-
- `--ota` (store_true, default: False): Specify if the setup used is OTA or on Colosseum for determining the noise floor threshold. If the `noise_floor_threshold` parameter is specified, this parameter is ignored
|
|
85
|
-
- `--energy-gui` (store_true, default: False): Set whether to enable the energy GUI
|
|
86
|
-
- `--iq-plotter-gui` (store_true, default: False): Set whether to enable the IQ Plotter GUI
|
|
87
|
-
- `--demo-gui` (store_true, default: False): Set whether to enable the Demo GUI
|
|
88
|
-
- `--num-prbs` (int, default: 106): Number of PRBs
|
|
89
|
-
- `--num-subcarrier-spacing` (int, default: 30): Subcarrier spacing in kHz (FR1 is 30)
|
|
90
|
-
- `--e` (store_true, default: False): Set if 3/4 sampling for FFT size is set on the gNB (-E option on OAI)
|
|
91
|
-
- `--center-freq` (float, default: 3.6192e9): Center frequency in Hz
|
|
92
|
-
- `--timed` (store_true, default: False): Run with a 5-minute time limit
|
|
93
|
-
- `--model` (str, default: ''): Path to the CNN model file to be used
|
|
94
|
-
- `--time-window` (int, default: 5): Number of input vectors to pass to the CNN model
|
|
95
|
-
- `--moving-avg-window` (int, default: 30): Window size (in samples) for the moving average used to detect energy peaks in the spectrum
|
|
96
|
-
- `--extraction-window` (int, default: 600): Number of samples to retain after detecting an energy peak
|
|
97
78
|
|
|
79
|
+
**Command-line arguments:**
|
|
80
|
+
|
|
81
|
+
**Connection Configuration:**
|
|
82
|
+
- `--link` - Specify the link layer to be used. Options: `zmq`, `posix` (default: `zmq`)
|
|
83
|
+
- `--transport` - Specify the transport layer to be used. Options: `ipc`, `tcp` (default: `ipc`)
|
|
84
|
+
|
|
85
|
+
**Data Collection and Control:**
|
|
86
|
+
- `--save-iqs` - Enable data collection mode. When set, I/Q samples will be saved to disk for later analysis using SigMF
|
|
87
|
+
- `--control` - Enable PRB control. When set, the dApp will actively control spectrum allocation based on detected interference. If not set, the dApp can still receive and implement control action from an external xApp
|
|
88
|
+
|
|
89
|
+
**Spectrum Sensing Configuration:**
|
|
90
|
+
- `--noise-floor-threshold` - Set the noise floor threshold (in dB) for determining the presence of incumbents and for detecting the PRBs affected. If not specified, will be auto-detected based on environment
|
|
91
|
+
- `--ota` - Specify if the setup is Over-The-Air (OTA) or on Colosseum testbed for using a precalculated noise floor threshold. If `--noise-floor-threshold` is specified, this parameter is ignored
|
|
92
|
+
|
|
93
|
+
**Visualization Options:**
|
|
94
|
+
- `--energy-gui` - Enable the energy spectrum visualization GUI
|
|
95
|
+
- `--iq-plotter-gui` - Enable the I/Q constellation plotter GUI
|
|
96
|
+
- `--demo-gui` - Enable the demonstration GUI showing real-time spectrum occupancy
|
|
97
|
+
|
|
98
|
+
**Radio Configuration:**
|
|
99
|
+
- `--num-prbs` - Number of Physical Resource Blocks in the channel (default: 106)
|
|
100
|
+
- `--num-subcarrier-spacing` - Subcarrier spacing in kHz. Use 30 for FR1 (sub-6 GHz) (default: 30)
|
|
101
|
+
- `--e` - Enable 3/4 FFT sampling mode. Set this flag if the gNB was started with the `-E` option
|
|
102
|
+
- `--center-freq` - Center frequency in Hz (default: 3.6192e9, which is 3.6192 GHz)
|
|
103
|
+
|
|
104
|
+
**Execution Control:**
|
|
105
|
+
- `--timed SECONDS` - Run the dApp with a time limit (in seconds). Set to 0 for no limit (default: 0)
|
|
106
|
+
|
|
107
|
+
**AI/ML Model Configuration:**
|
|
108
|
+
- `--model` - Path to a pre-trained CNN model file for spectrum classification. If not provided, uses rule-based detection
|
|
109
|
+
- `--time-window` - Number of consecutive spectrum vectors to use as input for the CNN model (default: 5)
|
|
110
|
+
|
|
111
|
+
**Signal Processing Parameters:**
|
|
112
|
+
- `--moving-avg-window` - Window size (in samples) for the moving average filter used to smooth energy measurements and detect peaks in the spectrum (default: 30)
|
|
113
|
+
- `--extraction-window` - Number of samples to retain after detecting an energy peak for further analysis (default: 600)
|
|
114
|
+
- `--sampling-threshold` - Down-sampling ratio applied to IQ sensing. An IQ vector will be delivered every Nth sensing (default: 5)
|
|
98
115
|
|
|
99
116
|
If you use the dApp concept and/or the framework to develop your own dApps, please cite the following paper:
|
|
100
117
|
|
|
@@ -112,3 +129,73 @@ keywords = {Open RAN, dApps, Real-time control loops, Radio Resource Management
|
|
|
112
129
|
abstract = {Open Radio Access Networks (RANs) leverage disaggregated and programmable RAN functions and open interfaces to enable closed-loop, data-driven radio resource management. This is performed through custom intelligent applications on the RAN Intelligent Controllers (RICs), optimizing RAN policy scheduling, network slicing, user session management, and medium access control, among others. In this context, we have proposed dApps as a key extension of the O-RAN architecture into the real-time and user-plane domains. Deployed directly on RAN nodes, dApps access data otherwise unavailable to RICs due to privacy or timing constraints, enabling the execution of control actions within shorter time intervals. In this paper, we propose for the first time a reference architecture for dApps, defining their life cycle from deployment by the Service Management and Orchestration (SMO) to real-time control loop interactions with the RAN nodes where they are hosted. We introduce a new dApp interface, E3, along with an Application Protocol (AP) that supports structured message exchanges and extensible communication for various service models. By bridging E3 with the existing O-RAN E2 interface, we enable dApps, xApps, and rApps to coexist and coordinate. These applications can then collaborate on complex use cases and employ hierarchical control to resolve shared resource conflicts. Finally, we present and open-source a dApp framework based on OpenAirInterface (OAI). We benchmark its performance in two real-time control use cases, i.e., spectrum sharing and positioning in a 5th generation (5G) Next Generation Node Base (gNB) scenario. Our experimental results show that standardized real-time control loops via dApps are feasible, achieving average control latency below 450microseconds and allowing optimal use of shared spectral resources.}
|
|
113
130
|
}
|
|
114
131
|
```
|
|
132
|
+
|
|
133
|
+
## E3 Service Model Generator
|
|
134
|
+
|
|
135
|
+
The `tools/generate_sm.sh` script helps you create skeleton code for new E3 Service Models. This automates the creation of boilerplate code for both the agent (OAI) and dApp sides.
|
|
136
|
+
|
|
137
|
+
### Usage
|
|
138
|
+
|
|
139
|
+
**Interactive mode (recommended for first-time users):**
|
|
140
|
+
```bash
|
|
141
|
+
cd tools
|
|
142
|
+
./generate_sm.sh --interactive
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Command-line mode:**
|
|
146
|
+
```bash
|
|
147
|
+
./generate_sm.sh -n <sm_name> -a <asn_file> [OPTIONS]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Options:**
|
|
151
|
+
- `-n, --name NAME` - Service Model name (required)
|
|
152
|
+
- `-a, --asn-file FILE` - ASN.1 definition file path (required)
|
|
153
|
+
- `-t, --target TARGET` - Target: `agent`, `dapp`, or `both` (default: both)
|
|
154
|
+
- `-r, --ran-functions IDS` - Comma-separated RAN function IDs (e.g., 2,3,4)
|
|
155
|
+
- `-f, --format FORMAT` - Encoding format: `asn1` or `json` (default: asn1)
|
|
156
|
+
- `--agent-root PATH` - Path to OAI repository (or set `AGENT_ROOT` env var)
|
|
157
|
+
- `-i, --interactive` - Interactive mode with prompts
|
|
158
|
+
- `-h, --help` - Show help message
|
|
159
|
+
|
|
160
|
+
**Examples:**
|
|
161
|
+
```bash
|
|
162
|
+
# Generate both agent and dApp code for positioning SM
|
|
163
|
+
cd tools
|
|
164
|
+
./generate_sm.sh -n positioning -a positioning.asn -r 2 --agent-root /path/to/spear-openairinterface5g
|
|
165
|
+
|
|
166
|
+
# Generate only dApp code for KPM SM
|
|
167
|
+
./generate_sm.sh -n kpm -a kpm.asn -r 3,4 -t dapp
|
|
168
|
+
|
|
169
|
+
# Interactive mode
|
|
170
|
+
./generate_sm.sh --interactive
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Generated Structure:**
|
|
174
|
+
|
|
175
|
+
For agent-side (when `--target agent` or `both`):
|
|
176
|
+
```
|
|
177
|
+
spear-openairinterface5g/openair2/E3AP/service_models/<sm_name>_sm/
|
|
178
|
+
├── <sm_name>_sm.h # Main SM header
|
|
179
|
+
├── <sm_name>_sm.c # Main SM implementation
|
|
180
|
+
├── <sm_name>_enc.h/.c # Encoding functions
|
|
181
|
+
├── <sm_name>_dec.h/.c # Decoding functions
|
|
182
|
+
├── CMakeLists.txt # Build configuration
|
|
183
|
+
└── MESSAGES/
|
|
184
|
+
├── CMakeLists.txt
|
|
185
|
+
└── ASN1/V1/
|
|
186
|
+
├── e3sm_<sm_name>.asn
|
|
187
|
+
└── e3sm_<sm_name>.cmake
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
For dApp-side (when `--target dapp` or `both`):
|
|
191
|
+
```
|
|
192
|
+
spear-dApp/src/<sm_name>/
|
|
193
|
+
├── __init__.py
|
|
194
|
+
├── <sm_name>_dapp.py # Main dApp implementation
|
|
195
|
+
└── defs/
|
|
196
|
+
└── e3sm_<sm_name>.asn # ASN.1 schema
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Contributing
|
|
200
|
+
|
|
201
|
+
Contributions are welcome, but they must follow the guidelines in [CONTRIBUTING.md](./CONTRIBUTING.md)
|
dapps-0.0.6/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# dApp Library
|
|
2
|
+
|
|
3
|
+
A complete tutorial on how to deploy a dApp can be found on the [OpenRAN Gym website](https://openrangym.com/tutorials/dapps-oai). Please refer to that guide to instrument your system.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Python package installation (recommended)
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
pip3 install dapps[all]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The dApp can be found in the `examples` directory or it can be downloaded from this repository.
|
|
14
|
+
|
|
15
|
+
### Manual installation (use only for library development)
|
|
16
|
+
|
|
17
|
+
Clone the repository and install it manually with:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
hatch build
|
|
21
|
+
pip3 install "dist/*.tar.gz[all]"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Launch the Spectrum Sharing dApp example
|
|
25
|
+
|
|
26
|
+
OAI should start _before_ running the dApp
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
python3 examples/spectrum_dapp.py
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This dApp implements a spectrum sharing use case discussed in [our paper](https://doi.org/10.1016/j.comnet.2025.111342) ([here for the archive version](https://arxiv.org/pdf/2501.16502)).
|
|
33
|
+
|
|
34
|
+
**Command-line arguments:**
|
|
35
|
+
|
|
36
|
+
**Connection Configuration:**
|
|
37
|
+
- `--link` - Specify the link layer to be used. Options: `zmq`, `posix` (default: `zmq`)
|
|
38
|
+
- `--transport` - Specify the transport layer to be used. Options: `ipc`, `tcp` (default: `ipc`)
|
|
39
|
+
|
|
40
|
+
**Data Collection and Control:**
|
|
41
|
+
- `--save-iqs` - Enable data collection mode. When set, I/Q samples will be saved to disk for later analysis using SigMF
|
|
42
|
+
- `--control` - Enable PRB control. When set, the dApp will actively control spectrum allocation based on detected interference. If not set, the dApp can still receive and implement control action from an external xApp
|
|
43
|
+
|
|
44
|
+
**Spectrum Sensing Configuration:**
|
|
45
|
+
- `--noise-floor-threshold` - Set the noise floor threshold (in dB) for determining the presence of incumbents and for detecting the PRBs affected. If not specified, will be auto-detected based on environment
|
|
46
|
+
- `--ota` - Specify if the setup is Over-The-Air (OTA) or on Colosseum testbed for using a precalculated noise floor threshold. If `--noise-floor-threshold` is specified, this parameter is ignored
|
|
47
|
+
|
|
48
|
+
**Visualization Options:**
|
|
49
|
+
- `--energy-gui` - Enable the energy spectrum visualization GUI
|
|
50
|
+
- `--iq-plotter-gui` - Enable the I/Q constellation plotter GUI
|
|
51
|
+
- `--demo-gui` - Enable the demonstration GUI showing real-time spectrum occupancy
|
|
52
|
+
|
|
53
|
+
**Radio Configuration:**
|
|
54
|
+
- `--num-prbs` - Number of Physical Resource Blocks in the channel (default: 106)
|
|
55
|
+
- `--num-subcarrier-spacing` - Subcarrier spacing in kHz. Use 30 for FR1 (sub-6 GHz) (default: 30)
|
|
56
|
+
- `--e` - Enable 3/4 FFT sampling mode. Set this flag if the gNB was started with the `-E` option
|
|
57
|
+
- `--center-freq` - Center frequency in Hz (default: 3.6192e9, which is 3.6192 GHz)
|
|
58
|
+
|
|
59
|
+
**Execution Control:**
|
|
60
|
+
- `--timed SECONDS` - Run the dApp with a time limit (in seconds). Set to 0 for no limit (default: 0)
|
|
61
|
+
|
|
62
|
+
**AI/ML Model Configuration:**
|
|
63
|
+
- `--model` - Path to a pre-trained CNN model file for spectrum classification. If not provided, uses rule-based detection
|
|
64
|
+
- `--time-window` - Number of consecutive spectrum vectors to use as input for the CNN model (default: 5)
|
|
65
|
+
|
|
66
|
+
**Signal Processing Parameters:**
|
|
67
|
+
- `--moving-avg-window` - Window size (in samples) for the moving average filter used to smooth energy measurements and detect peaks in the spectrum (default: 30)
|
|
68
|
+
- `--extraction-window` - Number of samples to retain after detecting an energy peak for further analysis (default: 600)
|
|
69
|
+
- `--sampling-threshold` - Down-sampling ratio applied to IQ sensing. An IQ vector will be delivered every Nth sensing (default: 5)
|
|
70
|
+
|
|
71
|
+
If you use the dApp concept and/or the framework to develop your own dApps, please cite the following paper:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
@article{LACAVA2025111342,
|
|
75
|
+
title = {{dApps: Enabling Real-Time AI-based Open RAN Control}},
|
|
76
|
+
journal = {Computer Networks},
|
|
77
|
+
pages = {111342},
|
|
78
|
+
year = {2025},
|
|
79
|
+
issn = {1389-1286},
|
|
80
|
+
doi = {https://doi.org/10.1016/j.comnet.2025.111342},
|
|
81
|
+
url = {https://www.sciencedirect.com/science/article/pii/S1389128625003093},
|
|
82
|
+
author = {Andrea Lacava and Leonardo Bonati and Niloofar Mohamadi and Rajeev Gangula and Florian Kaltenberger and Pedram Johari and Salvatore D’Oro and Francesca Cuomo and Michele Polese and Tommaso Melodia},
|
|
83
|
+
keywords = {Open RAN, dApps, Real-time control loops, Radio Resource Management (RRM), Spectrum sharing, Positioning, Integrated Sensing and Communication (ISAC)},
|
|
84
|
+
abstract = {Open Radio Access Networks (RANs) leverage disaggregated and programmable RAN functions and open interfaces to enable closed-loop, data-driven radio resource management. This is performed through custom intelligent applications on the RAN Intelligent Controllers (RICs), optimizing RAN policy scheduling, network slicing, user session management, and medium access control, among others. In this context, we have proposed dApps as a key extension of the O-RAN architecture into the real-time and user-plane domains. Deployed directly on RAN nodes, dApps access data otherwise unavailable to RICs due to privacy or timing constraints, enabling the execution of control actions within shorter time intervals. In this paper, we propose for the first time a reference architecture for dApps, defining their life cycle from deployment by the Service Management and Orchestration (SMO) to real-time control loop interactions with the RAN nodes where they are hosted. We introduce a new dApp interface, E3, along with an Application Protocol (AP) that supports structured message exchanges and extensible communication for various service models. By bridging E3 with the existing O-RAN E2 interface, we enable dApps, xApps, and rApps to coexist and coordinate. These applications can then collaborate on complex use cases and employ hierarchical control to resolve shared resource conflicts. Finally, we present and open-source a dApp framework based on OpenAirInterface (OAI). We benchmark its performance in two real-time control use cases, i.e., spectrum sharing and positioning in a 5th generation (5G) Next Generation Node Base (gNB) scenario. Our experimental results show that standardized real-time control loops via dApps are feasible, achieving average control latency below 450microseconds and allowing optimal use of shared spectral resources.}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## E3 Service Model Generator
|
|
89
|
+
|
|
90
|
+
The `tools/generate_sm.sh` script helps you create skeleton code for new E3 Service Models. This automates the creation of boilerplate code for both the agent (OAI) and dApp sides.
|
|
91
|
+
|
|
92
|
+
### Usage
|
|
93
|
+
|
|
94
|
+
**Interactive mode (recommended for first-time users):**
|
|
95
|
+
```bash
|
|
96
|
+
cd tools
|
|
97
|
+
./generate_sm.sh --interactive
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Command-line mode:**
|
|
101
|
+
```bash
|
|
102
|
+
./generate_sm.sh -n <sm_name> -a <asn_file> [OPTIONS]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Options:**
|
|
106
|
+
- `-n, --name NAME` - Service Model name (required)
|
|
107
|
+
- `-a, --asn-file FILE` - ASN.1 definition file path (required)
|
|
108
|
+
- `-t, --target TARGET` - Target: `agent`, `dapp`, or `both` (default: both)
|
|
109
|
+
- `-r, --ran-functions IDS` - Comma-separated RAN function IDs (e.g., 2,3,4)
|
|
110
|
+
- `-f, --format FORMAT` - Encoding format: `asn1` or `json` (default: asn1)
|
|
111
|
+
- `--agent-root PATH` - Path to OAI repository (or set `AGENT_ROOT` env var)
|
|
112
|
+
- `-i, --interactive` - Interactive mode with prompts
|
|
113
|
+
- `-h, --help` - Show help message
|
|
114
|
+
|
|
115
|
+
**Examples:**
|
|
116
|
+
```bash
|
|
117
|
+
# Generate both agent and dApp code for positioning SM
|
|
118
|
+
cd tools
|
|
119
|
+
./generate_sm.sh -n positioning -a positioning.asn -r 2 --agent-root /path/to/spear-openairinterface5g
|
|
120
|
+
|
|
121
|
+
# Generate only dApp code for KPM SM
|
|
122
|
+
./generate_sm.sh -n kpm -a kpm.asn -r 3,4 -t dapp
|
|
123
|
+
|
|
124
|
+
# Interactive mode
|
|
125
|
+
./generate_sm.sh --interactive
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Generated Structure:**
|
|
129
|
+
|
|
130
|
+
For agent-side (when `--target agent` or `both`):
|
|
131
|
+
```
|
|
132
|
+
spear-openairinterface5g/openair2/E3AP/service_models/<sm_name>_sm/
|
|
133
|
+
├── <sm_name>_sm.h # Main SM header
|
|
134
|
+
├── <sm_name>_sm.c # Main SM implementation
|
|
135
|
+
├── <sm_name>_enc.h/.c # Encoding functions
|
|
136
|
+
├── <sm_name>_dec.h/.c # Decoding functions
|
|
137
|
+
├── CMakeLists.txt # Build configuration
|
|
138
|
+
└── MESSAGES/
|
|
139
|
+
├── CMakeLists.txt
|
|
140
|
+
└── ASN1/V1/
|
|
141
|
+
├── e3sm_<sm_name>.asn
|
|
142
|
+
└── e3sm_<sm_name>.cmake
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For dApp-side (when `--target dapp` or `both`):
|
|
146
|
+
```
|
|
147
|
+
spear-dApp/src/<sm_name>/
|
|
148
|
+
├── __init__.py
|
|
149
|
+
├── <sm_name>_dapp.py # Main dApp implementation
|
|
150
|
+
└── defs/
|
|
151
|
+
└── e3sm_<sm_name>.asn # ASN.1 schema
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Contributing
|
|
155
|
+
|
|
156
|
+
Contributions are welcome, but they must follow the guidelines in [CONTRIBUTING.md](./CONTRIBUTING.md)
|
dapps-0.0.6/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.6
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
@startuml
|
|
2
|
+
!theme mars
|
|
3
|
+
skinparam defaultFontSize 20
|
|
4
|
+
skinparam classFontSize 22
|
|
5
|
+
skinparam backgroundColor transparent
|
|
6
|
+
left to right direction
|
|
7
|
+
skinparam linetype ortho
|
|
8
|
+
!define AbstractClass class
|
|
9
|
+
hide empty members
|
|
10
|
+
hide circles
|
|
11
|
+
|
|
12
|
+
class E3Interface {
|
|
13
|
+
-- Attributes --
|
|
14
|
+
- _instance : E3Interface
|
|
15
|
+
- _lock : threading.Lock
|
|
16
|
+
- callbacks : dict[int, list]
|
|
17
|
+
- stop_event : multiprocessing.Event
|
|
18
|
+
- initialized : bool
|
|
19
|
+
- _message_id_counter : int
|
|
20
|
+
- _message_id_lock : threading.Lock
|
|
21
|
+
- e3_connector : E3Connector
|
|
22
|
+
- encoder : E3Encoder
|
|
23
|
+
- outbound_queue : multiprocessing.Queue
|
|
24
|
+
- inbound_process : multiprocessing.Process
|
|
25
|
+
- outbound_process : multiprocessing.Process
|
|
26
|
+
-- Methods --
|
|
27
|
+
__new__()
|
|
28
|
+
__init__(encoder: E3Encoder, **kwargs)
|
|
29
|
+
Note: kwargs can include: link (str), transport (str)
|
|
30
|
+
+ send_setup_request(dappId: int) : bool | list
|
|
31
|
+
+ send_subscription_request(ranFunctionId: int, dappId: int, actionType: str) : bool
|
|
32
|
+
+ send_message_ack(requestId: int, responseCode: str)
|
|
33
|
+
+ setup_connections()
|
|
34
|
+
+ add_callback(dapp_id: int, callback)
|
|
35
|
+
+ remove_callback(dapp_id: int, callback=None)
|
|
36
|
+
+ schedule_control(dappId: int, actionData: bytes)
|
|
37
|
+
+ schedule_report(reportData: bytes)
|
|
38
|
+
+ terminate_connections()
|
|
39
|
+
- _inbound_connection()
|
|
40
|
+
- _outbound_connection()
|
|
41
|
+
- _handle_incoming_data(dapp_identifier: int, data)
|
|
42
|
+
- _get_next_message_id() : int
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
AbstractClass SpectrumSharingDApp {
|
|
46
|
+
-- Attributes --
|
|
47
|
+
- spectrum_encoder : asn1tools.Compiler
|
|
48
|
+
- _sampling_threshold_control_callback : callable
|
|
49
|
+
- num_consecutive_subcarriers_for_prb : int
|
|
50
|
+
- num_prbs : int
|
|
51
|
+
- num_subcarrier_spacing : int
|
|
52
|
+
- ofdm_symbol_size : int
|
|
53
|
+
- bw : float
|
|
54
|
+
- center_freq : float
|
|
55
|
+
- fft_size : int
|
|
56
|
+
- first_carrier_offset : int
|
|
57
|
+
- prb_thrs : int
|
|
58
|
+
- average_over_frames : int
|
|
59
|
+
- noise_floor_threshold : int
|
|
60
|
+
- save_iqs : bool
|
|
61
|
+
- sampling_threshold : int
|
|
62
|
+
- iq_save_file : file
|
|
63
|
+
- save_counter : int
|
|
64
|
+
- limit_per_file : int
|
|
65
|
+
- control : bool
|
|
66
|
+
- energyGui : bool
|
|
67
|
+
- iqPlotterGui : bool
|
|
68
|
+
- dashboard : bool
|
|
69
|
+
- control_count : int
|
|
70
|
+
- abs_iq_av : np.ndarray
|
|
71
|
+
- sig_queue : multiprocessing.Queue (optional, if energyGui=True)
|
|
72
|
+
- energyPlotter : EnergyPlotter (optional, if energyGui=True)
|
|
73
|
+
- iq_queue : multiprocessing.Queue (optional, if iqPlotterGui=True)
|
|
74
|
+
- iqPlotter : IQPlotter (optional, if iqPlotterGui=True)
|
|
75
|
+
- demo_queue : multiprocessing.Queue (optional, if dashboard=True)
|
|
76
|
+
- demo : Dashboard (optional, if dashboard=True)
|
|
77
|
+
-- Methods --
|
|
78
|
+
__init__(id: int, link: str, transport: str, noise_floor_threshold: int, save_iqs: bool, control: bool, center_freq: float, num_prbs: int, num_subcarrier_spacing: int, e_sampling: bool, encoding_method: str, sampling_threshold: int, **kwargs)
|
|
79
|
+
Note: kwargs can include: energyGui, iqPlotterGui, dashboard, classifier
|
|
80
|
+
- _init_spectrum_encoder()
|
|
81
|
+
+ set_sampling_threshold_control_logic(callback)
|
|
82
|
+
+ create_prb_blacklist_control(blacklisted_prbs: bytes, prb_count: int, sampling_period_ms: int, action_definition: str) : bytes
|
|
83
|
+
+ decode_iq_data_indication(data: bytes) : dict
|
|
84
|
+
+ decode_config_control(data: bytes) : dict
|
|
85
|
+
+ get_iqs_from_ran(dapp_identifier: int, data: bytes)
|
|
86
|
+
# _control_loop()
|
|
87
|
+
# _stop()
|
|
88
|
+
- _encode_spectrum_message(message_type: str, data: dict) : bytes
|
|
89
|
+
- _decode_spectrum_message(message_type: str, data: bytes) : dict
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
AbstractClass DApp {
|
|
94
|
+
-- Attributes --
|
|
95
|
+
- dapp_id : int
|
|
96
|
+
- encoding_method : str
|
|
97
|
+
- e3_interface : E3Interface
|
|
98
|
+
- stop_event : multiprocessing.Event
|
|
99
|
+
-- Methods --
|
|
100
|
+
__init__(id: int, link: str, transport: str, callbacks: list, encoding_method: str, **kwargs)
|
|
101
|
+
+ setup_connection() : bool, list
|
|
102
|
+
+ send_subscription_request(ranFunctionIds: list)
|
|
103
|
+
+ control_loop()
|
|
104
|
+
+ stop()
|
|
105
|
+
# _control_loop() : abstract
|
|
106
|
+
# _stop() : abstract
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
class E3LinkLayer {
|
|
110
|
+
-- Enumeration --
|
|
111
|
+
+ ZMQ = "zmq"
|
|
112
|
+
+ POSIX = "posix"
|
|
113
|
+
-- Methods --
|
|
114
|
+
+ from_string(link_layer_str: str)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
class E3TransportLayer {
|
|
118
|
+
-- Enumeration --
|
|
119
|
+
+ SCTP = "sctp"
|
|
120
|
+
+ TCP = "tcp"
|
|
121
|
+
+ IPC = "ipc"
|
|
122
|
+
-- Methods --
|
|
123
|
+
+ from_string(transport_layer_str: str)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
AbstractClass E3Connector {
|
|
127
|
+
-- Attributes --
|
|
128
|
+
- VALID_CONFIGURATIONS : list
|
|
129
|
+
- E3_IPC_SETUP_PATH : str
|
|
130
|
+
- E3_IPC_SOCKET_PATH : str
|
|
131
|
+
- DAPP_IPC_SOCKET_PATH : str
|
|
132
|
+
-- Methods --
|
|
133
|
+
+ setup_connector(link_layer: str, transport_layer: str)
|
|
134
|
+
+ send_setup_request(payload: bytes)
|
|
135
|
+
+ setup_inbound_connection()
|
|
136
|
+
+ setup_outbound_connection()
|
|
137
|
+
+ send(payload: bytes)
|
|
138
|
+
+ receive() : bytes
|
|
139
|
+
+ dispose()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
class ZMQConnector {
|
|
143
|
+
-- Attributes --
|
|
144
|
+
- setup_context : zmq.Context
|
|
145
|
+
- inbound_context : zmq.Context
|
|
146
|
+
- outbound_context : zmq.Context
|
|
147
|
+
- transport_layer : E3TransportLayer
|
|
148
|
+
-- Methods --
|
|
149
|
+
+ __init__(transport_layer: E3TransportLayer)
|
|
150
|
+
+ send_setup_request(payload: bytes)
|
|
151
|
+
+ setup_inbound_connection()
|
|
152
|
+
+ setup_outbound_connection()
|
|
153
|
+
+ send(payload: bytes)
|
|
154
|
+
+ receive() : bytes
|
|
155
|
+
+ dispose()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
class POSIXConnector {
|
|
159
|
+
-- Attributes --
|
|
160
|
+
- transport_layer : E3TransportLayer
|
|
161
|
+
- CHUNK_SIZE : int
|
|
162
|
+
-- Methods --
|
|
163
|
+
+ __init__(transport_layer: E3TransportLayer)
|
|
164
|
+
+ send_setup_request(payload: bytes)
|
|
165
|
+
+ setup_inbound_connection()
|
|
166
|
+
+ setup_outbound_connection()
|
|
167
|
+
+ send(payload: bytes)
|
|
168
|
+
+ receive() : bytes
|
|
169
|
+
+ dispose()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
AbstractClass E3Encoder {
|
|
173
|
+
-- Attributes --
|
|
174
|
+
- encoding_type : str
|
|
175
|
+
-- Methods --
|
|
176
|
+
+ encode_pdu(pdu_type: str, pdu_data: dict) : bytes
|
|
177
|
+
+ decode_pdu(data: bytes) : tuple
|
|
178
|
+
+ create_setup_request(dappId: int, ranFunctions: list, msgId: int, actionType: str) : bytes
|
|
179
|
+
+ create_subscription_request(msgId: int, dappId: int, actionType: str, ranFunctionId: int) : bytes
|
|
180
|
+
+ create_message_ack(msgId: int, requestId: int, responseCode: str) : bytes
|
|
181
|
+
+ create_control_action(msgId: int, dappId: int, actionData: bytes) : bytes
|
|
182
|
+
+ create_dapp_report(msgId: int, reportData: bytes) : bytes
|
|
183
|
+
+ create_indication_message(msgId: int, protocolData: bytes) : bytes
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
class AsnE3Encoder {
|
|
187
|
+
-- Attributes --
|
|
188
|
+
- defs : asn1tools.Compiler
|
|
189
|
+
-- Methods --
|
|
190
|
+
+ __init__(asn_file_path: str)
|
|
191
|
+
+ encode_pdu(pdu_type: str, pdu_data: dict) : bytes
|
|
192
|
+
+ decode_pdu(data: bytes) : tuple
|
|
193
|
+
+ create_setup_request(dappId: int, ranFunctions: list, msgId: int, actionType: str) : bytes
|
|
194
|
+
+ create_subscription_request(msgId: int, dappId: int, actionType: str, ranFunctionId: int) : bytes
|
|
195
|
+
+ create_message_ack(msgId: int, requestId: int, responseCode: str) : bytes
|
|
196
|
+
+ create_control_action(msgId: int, dappId: int, actionData: bytes) : bytes
|
|
197
|
+
+ create_dapp_report(msgId: int, reportData: bytes) : bytes
|
|
198
|
+
+ create_indication_message(msgId: int, protocolData: bytes) : bytes
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
DApp --> E3Interface
|
|
202
|
+
DApp <|-- SpectrumSharingDApp
|
|
203
|
+
E3Connector <|-- ZMQConnector
|
|
204
|
+
E3Connector <|-- POSIXConnector
|
|
205
|
+
E3Encoder <|-- AsnE3Encoder
|
|
206
|
+
E3Interface --* E3Connector
|
|
207
|
+
E3Interface --* E3Encoder
|
|
208
|
+
E3Connector --> E3LinkLayer
|
|
209
|
+
E3Connector --> E3TransportLayer
|
|
210
|
+
@enduml
|