mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-17 22:50:31 +00:00
Compare commits
365 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ef5fafe89 | ||
|
|
9f6e46bd8a | ||
|
|
7372378732 | ||
|
|
71d20e0543 | ||
|
|
33fd2343ce | ||
|
|
48ef96959d | ||
|
|
c73ce11828 | ||
|
|
66546b7ad0 | ||
|
|
11087fff0f | ||
|
|
ffa13d99e5 | ||
|
|
ccae22f648 | ||
|
|
4e932c9248 | ||
|
|
0c9dd4d04a | ||
|
|
67a5bfaa43 | ||
|
|
501192a1f8 | ||
|
|
83d00d4c21 | ||
|
|
12504106eb | ||
|
|
3bb957722f | ||
|
|
ae2abbc6e2 | ||
|
|
544c723372 | ||
|
|
1e34ab443c | ||
|
|
519b38817a | ||
|
|
3da668576c | ||
|
|
ce46cab866 | ||
|
|
553c6377aa | ||
|
|
b42694254f | ||
|
|
50821cace3 | ||
|
|
2fb9752bff | ||
|
|
7b57a3d4ed | ||
|
|
d81b670ac2 | ||
|
|
461ba045b1 | ||
|
|
03a8ff2913 | ||
|
|
6e85528582 | ||
|
|
81ba755984 | ||
|
|
e8ca483c56 | ||
|
|
f8eba8400d | ||
|
|
6d2bd1025f | ||
|
|
36c0cf0133 | ||
|
|
7b31678bed | ||
|
|
b2ba88667a | ||
|
|
0aca093122 | ||
|
|
73f5496ffa | ||
|
|
f809e4689c | ||
|
|
5ae59cc394 | ||
|
|
def1ebc661 | ||
|
|
b57963dd2a | ||
|
|
d33ae02d39 | ||
|
|
86ba2b0822 | ||
|
|
4bfc929bad | ||
|
|
db81a3f0b9 | ||
|
|
abf14c0bb4 | ||
|
|
a1d4514ae0 | ||
|
|
d813fb8470 | ||
|
|
e2615dd886 | ||
|
|
cc24755a34 | ||
|
|
ca45cbb2b7 | ||
|
|
deb2a453c6 | ||
|
|
5a08d8109c | ||
|
|
65c858757d | ||
|
|
55003cafd2 | ||
|
|
57a7488e85 | ||
|
|
da85cf5183 | ||
|
|
32a6dd85c2 | ||
|
|
d9216265dc | ||
|
|
99ecd83133 | ||
|
|
c4958e50e8 | ||
|
|
7b16f7e863 | ||
|
|
e0c7980df5 | ||
|
|
4b002029fb | ||
|
|
27d626dc48 | ||
|
|
4fa9e2b39b | ||
|
|
fb5c768159 | ||
|
|
0966ceb70b | ||
|
|
b75d4f90b7 | ||
|
|
8cbe53b82b | ||
|
|
13e17339d3 | ||
|
|
6d457fcb56 | ||
|
|
748d4cb49a | ||
|
|
1e77b753ff | ||
|
|
2964ef7e3e | ||
|
|
7f69632bbb | ||
|
|
17af1562a8 | ||
|
|
c3378c7f84 | ||
|
|
38dca6387f | ||
|
|
4a42ff54df | ||
|
|
22d4495c20 | ||
|
|
3b93a9c5cb | ||
|
|
6407df90e2 | ||
|
|
d75da26833 | ||
|
|
b0f0106cc7 | ||
|
|
2690cbd08e | ||
|
|
868f9d9042 | ||
|
|
ad0dcfe287 | ||
|
|
7bd44da548 | ||
|
|
185e5934b7 | ||
|
|
24802ee18b | ||
|
|
8916cfdfd2 | ||
|
|
b135c1dd8f | ||
|
|
6e61c8a05a | ||
|
|
c957882da8 | ||
|
|
7404ad7a5c | ||
|
|
4e8fa01a25 | ||
|
|
ec0d3fde1c | ||
|
|
58618be544 | ||
|
|
7e7c097942 | ||
|
|
94796957e8 | ||
|
|
55d9200a48 | ||
|
|
d815edebe7 | ||
|
|
f1d18b4edb | ||
|
|
06355e9cf1 | ||
|
|
9bcf269856 | ||
|
|
9bfcbe7faa | ||
|
|
fa92bf1a79 | ||
|
|
a348ada211 | ||
|
|
e0f76e6ca6 | ||
|
|
351f069adc | ||
|
|
64f84cdd6a | ||
|
|
8bd1b3b53a | ||
|
|
2aef88960f | ||
|
|
51d6fd7ec2 | ||
|
|
f2d43636bf | ||
|
|
dbeda2d33f | ||
|
|
5d9f91997e | ||
|
|
210429f388 | ||
|
|
dc40e0dca1 | ||
|
|
fe8f418e7a | ||
|
|
98de3b9049 | ||
|
|
55d83f6045 | ||
|
|
6882b63991 | ||
|
|
45896f2583 | ||
|
|
ed6b13c759 | ||
|
|
eee4d3fc07 | ||
|
|
b8f64823bf | ||
|
|
d37952f94d | ||
|
|
12e2eded38 | ||
|
|
d910e92669 | ||
|
|
9e2f2db88c | ||
|
|
85929b7933 | ||
|
|
5673a31814 | ||
|
|
7da80421ff | ||
|
|
35e4f29cf6 | ||
|
|
c1abfcfc50 | ||
|
|
b2e8b78a01 | ||
|
|
53e160728a | ||
|
|
522f2ad140 | ||
|
|
4a26a44ee0 | ||
|
|
59722d1a91 | ||
|
|
218a524cd2 | ||
|
|
f44f105cb3 | ||
|
|
32ff4b33f1 | ||
|
|
bf0492ba87 | ||
|
|
7a9c13422a | ||
|
|
3e3b33e94c | ||
|
|
58ae227080 | ||
|
|
81a671a4f3 | ||
|
|
039c6d24bc | ||
|
|
ec80ef106f | ||
|
|
60f17d4d45 | ||
|
|
5e86379be4 | ||
|
|
62789c5161 | ||
|
|
bede89b233 | ||
|
|
4a29496988 | ||
|
|
a809a8c722 | ||
|
|
ad3ce4ddb6 | ||
|
|
72df29f225 | ||
|
|
42ab0247bf | ||
|
|
a439a0cce0 | ||
|
|
f7c9075337 | ||
|
|
15fc3ccce0 | ||
|
|
f2500d9297 | ||
|
|
72bc9baf2e | ||
|
|
6cef7a8f67 | ||
|
|
b32524dd74 | ||
|
|
a45dd3b8bc | ||
|
|
a981bb382b | ||
|
|
f17aba0f5e | ||
|
|
ca0398c5bc | ||
|
|
ab6bb2534e | ||
|
|
c875ce639c | ||
|
|
23a1d8d9bc | ||
|
|
c0f6b39da5 | ||
|
|
095be9fe6a | ||
|
|
82ebc9fa7b | ||
|
|
526720cb24 | ||
|
|
433dbcd41a | ||
|
|
20b3210062 | ||
|
|
b959af152d | ||
|
|
e5335a0188 | ||
|
|
1387bdc16e | ||
|
|
d2dfe830e7 | ||
|
|
3da8b0e5eb | ||
|
|
de0e075381 | ||
|
|
826b405d47 | ||
|
|
d761f67bcf | ||
|
|
975835804d | ||
|
|
b467fd2c68 | ||
|
|
daec2ba3ea | ||
|
|
e705c88dd5 | ||
|
|
7121bf6d05 | ||
|
|
1228608cc2 | ||
|
|
47ac986d8c | ||
|
|
8ea378eea8 | ||
|
|
2c688f230f | ||
|
|
cbec64c28f | ||
|
|
1c352f3138 | ||
|
|
5e964d660f | ||
|
|
2e66c87f4d | ||
|
|
82a771dd61 | ||
|
|
c99f52207d | ||
|
|
5091682551 | ||
|
|
3555edff76 | ||
|
|
6723fc531b | ||
|
|
26cc637d1b | ||
|
|
e63f1454b3 | ||
|
|
c69d980613 | ||
|
|
4c4917442f | ||
|
|
bfb06225a5 | ||
|
|
d62892ff8a | ||
|
|
78ed7d4570 | ||
|
|
d969a124ee | ||
|
|
b68e614850 | ||
|
|
17a4dea3e1 | ||
|
|
2cced7bdb5 | ||
|
|
43130b687e | ||
|
|
b7e026fda5 | ||
|
|
4662ccc46a | ||
|
|
ae54a1bd05 | ||
|
|
94ca30e82b | ||
|
|
fdf2728d02 | ||
|
|
2783acb933 | ||
|
|
df1cffbc7f | ||
|
|
e78e720a46 | ||
|
|
2d9bac6359 | ||
|
|
2ebb462a8e | ||
|
|
8ea5fd7894 | ||
|
|
c939a9cdf5 | ||
|
|
31c9a03e83 | ||
|
|
ff5ec94d33 | ||
|
|
d6e58c9436 | ||
|
|
5894bcac22 | ||
|
|
ef469b9b51 | ||
|
|
980bb2420b | ||
|
|
bf219fc24f | ||
|
|
b7b41fefc0 | ||
|
|
0b91791f67 | ||
|
|
29c5129b0a | ||
|
|
3b0f050a33 | ||
|
|
dc6dd67827 | ||
|
|
c5b8fa5418 | ||
|
|
1565667908 | ||
|
|
9f10bfebf2 | ||
|
|
b34a44a4f9 | ||
|
|
0b7201244a | ||
|
|
28bd9ea4bc | ||
|
|
044ed48fc7 | ||
|
|
586aa46c2c | ||
|
|
6f481e09f6 | ||
|
|
1b071df0bc | ||
|
|
45967c8b77 | ||
|
|
fc758069fb | ||
|
|
9be7b12654 | ||
|
|
160abd88cc | ||
|
|
e2eebc7a28 | ||
|
|
a52adaa95e | ||
|
|
ced3078e30 | ||
|
|
b7d2840e04 | ||
|
|
0a88f1a2d8 | ||
|
|
4855b4102d | ||
|
|
2dac45f1a3 | ||
|
|
e73acbc776 | ||
|
|
21d0fdb92a | ||
|
|
68e2cb7800 | ||
|
|
de24e2da1e | ||
|
|
bc4eb38eec | ||
|
|
8600b7815d | ||
|
|
8bee5da854 | ||
|
|
40bfb7b07a | ||
|
|
46c1dd511a | ||
|
|
d9cd942f3b | ||
|
|
147fb74085 | ||
|
|
7546e614c7 | ||
|
|
9a58bae112 | ||
|
|
9e99113aa1 | ||
|
|
ea4d82bc31 | ||
|
|
94efccba21 | ||
|
|
28c688b16f | ||
|
|
6d991456a9 | ||
|
|
bb840b7f7e | ||
|
|
9fecc570f8 | ||
|
|
1a5da9a1aa | ||
|
|
adb13cd4d4 | ||
|
|
9f8ebe86f4 | ||
|
|
46329a4f2d | ||
|
|
1f4dcc9fda | ||
|
|
7dda3dde08 | ||
|
|
e108aaa7db | ||
|
|
7da12ca861 | ||
|
|
2b987e8e00 | ||
|
|
c2106e49d8 | ||
|
|
0b473838fa | ||
|
|
3e15c59e00 | ||
|
|
9aa6e61197 | ||
|
|
4c58063268 | ||
|
|
25f1b46647 | ||
|
|
68ae77a79e | ||
|
|
a4ad969553 | ||
|
|
415e9e8495 | ||
|
|
5a5d8670ea | ||
|
|
9e20b2464f | ||
|
|
ea5c125dbd | ||
|
|
66646cd17a | ||
|
|
81b0df6f1d | ||
|
|
e9dadf1706 | ||
|
|
f9e45856fc | ||
|
|
0f9fcb3f0a | ||
|
|
17af664374 | ||
|
|
da3bda8bbb | ||
|
|
a5d66d1f4a | ||
|
|
4b289a53df | ||
|
|
d5eb164a20 | ||
|
|
fec25da5e7 | ||
|
|
4ec7d0a824 | ||
|
|
a873c0080a | ||
|
|
06f905853a | ||
|
|
179b8f57b3 | ||
|
|
9b1e5db390 | ||
|
|
32e5f13002 | ||
|
|
4497800fe1 | ||
|
|
6846459ea5 | ||
|
|
f7dafc4771 | ||
|
|
ee11159d5d | ||
|
|
c0a3b39688 | ||
|
|
679dcae557 | ||
|
|
b14c4b2aa6 | ||
|
|
92c534dcaa | ||
|
|
07fb404e33 | ||
|
|
a010b4d89f | ||
|
|
b340427363 | ||
|
|
654a2b7f63 | ||
|
|
b0cb9b8615 | ||
|
|
9bb75d82cf | ||
|
|
535239a5ae | ||
|
|
89b2a966ba | ||
|
|
29e2a542dd | ||
|
|
98a736c9d7 | ||
|
|
8404af8d18 | ||
|
|
7572d8cb46 | ||
|
|
db43c3e12e | ||
|
|
ea066dc0dc | ||
|
|
c0037b1f98 | ||
|
|
29aa6407be | ||
|
|
f6d4c77e75 | ||
|
|
c0e019efbd | ||
|
|
ded656208d | ||
|
|
9c36a8ebc2 | ||
|
|
1dda299dc3 | ||
|
|
c8d1b99e42 | ||
|
|
b274f3c8d3 | ||
|
|
1d7775875e | ||
|
|
3a560604ec | ||
|
|
f677cc34b3 | ||
|
|
cdab201890 | ||
|
|
20186aec26 | ||
|
|
79fc8623e3 | ||
|
|
c104b12302 |
20
.gitignore
vendored
20
.gitignore
vendored
@@ -9,29 +9,9 @@ cmake_targets/nas_sim_tools/build/
|
||||
log/
|
||||
lte_build_oai/
|
||||
targets/bin/
|
||||
core
|
||||
*.lseq
|
||||
*.lcheck
|
||||
*.out
|
||||
|
||||
# object files
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
.vscode/launch.json
|
||||
|
||||
# python virtual env
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
|
||||
# Tags for vim/global
|
||||
GPATH
|
||||
|
||||
31
.vscode/launch.json
vendored
31
.vscode/launch.json
vendored
@@ -1,31 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/cmake_targets/ran_build/build/lte-softmodem",
|
||||
"args": [
|
||||
"-O", "../ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf",
|
||||
"--noS1"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}/cmake_targets",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "${workspaceFolder}/cmake_targets/sudo-gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
Active_eNBs = ( "eNB-Eurecom-LTEBox");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
eNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
eNB_ID = 0xe00;
|
||||
|
||||
cell_type = "CELL_MACRO_ENB";
|
||||
|
||||
eNB_name = "eNB-Eurecom-LTEBox";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2; } );
|
||||
|
||||
tr_s_preference = "local_mac"
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
component_carriers = (
|
||||
{
|
||||
node_function = "3GPP_eNODEB";
|
||||
node_timing = "synch_to_ext_device";
|
||||
node_synch_ref = 0;
|
||||
frame_type = "FDD";
|
||||
tdd_config = 3;
|
||||
tdd_config_s = 0;
|
||||
prefix_type = "NORMAL";
|
||||
eutra_band = 7;
|
||||
downlink_frequency = 2680000000L;
|
||||
uplink_frequency_offset = -120000000;
|
||||
Nid_cell = 0;
|
||||
N_RB_DL = 50;
|
||||
Nid_cell_mbsfn = 0;
|
||||
nb_antenna_ports = 1;
|
||||
nb_antennas_tx = 1;
|
||||
nb_antennas_rx = 1;
|
||||
tx_gain = 90;
|
||||
rx_gain = 125;
|
||||
pbch_repetition = "FALSE";
|
||||
prach_root = 0;
|
||||
prach_config_index = 0;
|
||||
prach_high_speed = "DISABLE";
|
||||
prach_zero_correlation = 1;
|
||||
prach_freq_offset = 2;
|
||||
pucch_delta_shift = 1;
|
||||
pucch_nRB_CQI = 0;
|
||||
pucch_nCS_AN = 0;
|
||||
pucch_n1_AN = 0;
|
||||
pdsch_referenceSignalPower = -27;
|
||||
pdsch_p_b = 0;
|
||||
pusch_n_SB = 1;
|
||||
pusch_enable64QAM = "DISABLE";
|
||||
pusch_hoppingMode = "interSubFrame";
|
||||
pusch_hoppingOffset = 0;
|
||||
pusch_groupHoppingEnabled = "ENABLE";
|
||||
pusch_groupAssignment = 0;
|
||||
pusch_sequenceHoppingEnabled = "DISABLE";
|
||||
pusch_nDMRS1 = 1;
|
||||
phich_duration = "NORMAL";
|
||||
phich_resource = "ONESIXTH";
|
||||
srs_enable = "DISABLE";
|
||||
/* srs_BandwidthConfig =;
|
||||
srs_SubframeConfig =;
|
||||
srs_ackNackST =;
|
||||
srs_MaxUpPts =;*/
|
||||
|
||||
pusch_p0_Nominal = -96;
|
||||
pusch_alpha = "AL1";
|
||||
pucch_p0_Nominal = -104;
|
||||
msg3_delta_Preamble = 6;
|
||||
pucch_deltaF_Format1 = "deltaF2";
|
||||
pucch_deltaF_Format1b = "deltaF3";
|
||||
pucch_deltaF_Format2 = "deltaF0";
|
||||
pucch_deltaF_Format2a = "deltaF0";
|
||||
pucch_deltaF_Format2b = "deltaF0";
|
||||
|
||||
rach_numberOfRA_Preambles = 64;
|
||||
rach_preamblesGroupAConfig = "DISABLE";
|
||||
/*
|
||||
rach_sizeOfRA_PreamblesGroupA = ;
|
||||
rach_messageSizeGroupA = ;
|
||||
rach_messagePowerOffsetGroupB = ;
|
||||
*/
|
||||
rach_powerRampingStep = 4;
|
||||
rach_preambleInitialReceivedTargetPower = -108;
|
||||
rach_preambleTransMax = 10;
|
||||
rach_raResponseWindowSize = 10;
|
||||
rach_macContentionResolutionTimer = 48;
|
||||
rach_maxHARQ_Msg3Tx = 4;
|
||||
|
||||
pcch_default_PagingCycle = 128;
|
||||
pcch_nB = "oneT";
|
||||
bcch_modificationPeriodCoeff = 2;
|
||||
ue_TimersAndConstants_t300 = 1000;
|
||||
ue_TimersAndConstants_t301 = 1000;
|
||||
ue_TimersAndConstants_t310 = 1000;
|
||||
ue_TimersAndConstants_t311 = 10000;
|
||||
ue_TimersAndConstants_n310 = 20;
|
||||
ue_TimersAndConstants_n311 = 1;
|
||||
ue_TransmissionMode = 1;
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
srb1_parameters :
|
||||
{
|
||||
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
|
||||
timer_poll_retransmit = 80;
|
||||
|
||||
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
|
||||
timer_reordering = 35;
|
||||
|
||||
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
|
||||
timer_status_prohibit = 0;
|
||||
|
||||
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
|
||||
poll_pdu = 4;
|
||||
|
||||
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
|
||||
poll_byte = 99999;
|
||||
|
||||
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
|
||||
max_retx_threshold = 4;
|
||||
}
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
|
||||
////////// MME parameters:
|
||||
mme_ip_address = ( { ipv4 = "10.193.4.249";
|
||||
ipv6 = "";
|
||||
active = "yes";
|
||||
preference = "ipv4";
|
||||
}
|
||||
);
|
||||
|
||||
enable_measurement_reports = "no";
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth1";
|
||||
ENB_IPV4_ADDRESS_FOR_S1_MME = "10.193.4.248";
|
||||
ENB_INTERFACE_NAME_FOR_S1U = "eth1";
|
||||
ENB_IPV4_ADDRESS_FOR_S1U = "10.193.4.248";
|
||||
ENB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
ENB_IPV4_ADDRESS_FOR_X2C = "10.193.4.248";
|
||||
ENB_PORT_FOR_X2C = 36422; # Spec 36422
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
phy_test_mode = 0;
|
||||
puSch10xSnr = 160;
|
||||
puCch10xSnr = 160;
|
||||
#scheduler_mode = "fairRR";
|
||||
#scheduler_mode = "default";
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "yes"
|
||||
nb_tx = 1
|
||||
nb_rx = 1
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [7];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 120;
|
||||
eNB_instances = [0];
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
|
||||
parallel_config = "PARALLEL_SINGLE_THREAD";
|
||||
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
|
||||
worker_config = "WORKER_DISABLE";
|
||||
}
|
||||
);
|
||||
|
||||
NETWORK_CONTROLLER :
|
||||
{
|
||||
FLEXRAN_ENABLED = "no";
|
||||
FLEXRAN_INTERFACE_NAME = "lo";
|
||||
FLEXRAN_IPV4_ADDRESS = "127.0.0.1";
|
||||
FLEXRAN_PORT = 2210;
|
||||
FLEXRAN_CACHE = "/mnt/oai_agent_cache";
|
||||
FLEXRAN_AWAIT_RECONF = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level ="warn";
|
||||
global_log_verbosity ="high";
|
||||
hw_log_level ="warn";
|
||||
hw_log_verbosity ="high";
|
||||
phy_log_level ="warn";
|
||||
phy_log_verbosity ="high";
|
||||
mac_log_level ="warn";
|
||||
mac_log_verbosity ="high";
|
||||
rlc_log_level ="warn";
|
||||
rlc_log_verbosity ="high";
|
||||
pdcp_log_level ="warn";
|
||||
pdcp_log_verbosity ="high";
|
||||
rrc_log_level ="warn";
|
||||
rrc_log_verbosity ="high";
|
||||
};
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
Active_eNBs = ( "eNB-Eurecom-LTEBox");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
eNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
eNB_ID = 0xe00;
|
||||
|
||||
cell_type = "CELL_MACRO_ENB";
|
||||
|
||||
eNB_name = "eNB-Eurecom-LTEBox";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ( { mcc = 208; mnc = 92; mnc_length = 2; } );
|
||||
|
||||
tr_s_preference = "local_mac"
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
component_carriers = (
|
||||
{
|
||||
node_function = "3GPP_eNODEB";
|
||||
node_timing = "synch_to_ext_device";
|
||||
node_synch_ref = 0;
|
||||
frame_type = "FDD";
|
||||
tdd_config = 3;
|
||||
tdd_config_s = 0;
|
||||
prefix_type = "NORMAL";
|
||||
eutra_band = 7;
|
||||
downlink_frequency = 2680000000L;
|
||||
uplink_frequency_offset = -120000000;
|
||||
Nid_cell = 0;
|
||||
N_RB_DL = 50;
|
||||
Nid_cell_mbsfn = 0;
|
||||
nb_antenna_ports = 1;
|
||||
nb_antennas_tx = 1;
|
||||
nb_antennas_rx = 1;
|
||||
tx_gain = 90;
|
||||
rx_gain = 125;
|
||||
pbch_repetition = "FALSE";
|
||||
prach_root = 0;
|
||||
prach_config_index = 0;
|
||||
prach_high_speed = "DISABLE";
|
||||
prach_zero_correlation = 1;
|
||||
prach_freq_offset = 2;
|
||||
pucch_delta_shift = 1;
|
||||
pucch_nRB_CQI = 0;
|
||||
pucch_nCS_AN = 0;
|
||||
pucch_n1_AN = 0;
|
||||
pdsch_referenceSignalPower = -27;
|
||||
pdsch_p_b = 0;
|
||||
pusch_n_SB = 1;
|
||||
pusch_enable64QAM = "DISABLE";
|
||||
pusch_hoppingMode = "interSubFrame";
|
||||
pusch_hoppingOffset = 0;
|
||||
pusch_groupHoppingEnabled = "ENABLE";
|
||||
pusch_groupAssignment = 0;
|
||||
pusch_sequenceHoppingEnabled = "DISABLE";
|
||||
pusch_nDMRS1 = 1;
|
||||
phich_duration = "NORMAL";
|
||||
phich_resource = "ONESIXTH";
|
||||
srs_enable = "DISABLE";
|
||||
/* srs_BandwidthConfig =;
|
||||
srs_SubframeConfig =;
|
||||
srs_ackNackST =;
|
||||
srs_MaxUpPts =;*/
|
||||
|
||||
pusch_p0_Nominal = -96;
|
||||
pusch_alpha = "AL1";
|
||||
pucch_p0_Nominal = -104;
|
||||
msg3_delta_Preamble = 6;
|
||||
pucch_deltaF_Format1 = "deltaF2";
|
||||
pucch_deltaF_Format1b = "deltaF3";
|
||||
pucch_deltaF_Format2 = "deltaF0";
|
||||
pucch_deltaF_Format2a = "deltaF0";
|
||||
pucch_deltaF_Format2b = "deltaF0";
|
||||
|
||||
rach_numberOfRA_Preambles = 64;
|
||||
rach_preamblesGroupAConfig = "DISABLE";
|
||||
/*
|
||||
rach_sizeOfRA_PreamblesGroupA = ;
|
||||
rach_messageSizeGroupA = ;
|
||||
rach_messagePowerOffsetGroupB = ;
|
||||
*/
|
||||
rach_powerRampingStep = 4;
|
||||
rach_preambleInitialReceivedTargetPower = -108;
|
||||
rach_preambleTransMax = 10;
|
||||
rach_raResponseWindowSize = 10;
|
||||
rach_macContentionResolutionTimer = 48;
|
||||
rach_maxHARQ_Msg3Tx = 4;
|
||||
|
||||
pcch_default_PagingCycle = 128;
|
||||
pcch_nB = "oneT";
|
||||
bcch_modificationPeriodCoeff = 2;
|
||||
ue_TimersAndConstants_t300 = 1000;
|
||||
ue_TimersAndConstants_t301 = 1000;
|
||||
ue_TimersAndConstants_t310 = 1000;
|
||||
ue_TimersAndConstants_t311 = 10000;
|
||||
ue_TimersAndConstants_n310 = 20;
|
||||
ue_TimersAndConstants_n311 = 1;
|
||||
ue_TransmissionMode = 1;
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
srb1_parameters :
|
||||
{
|
||||
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
|
||||
timer_poll_retransmit = 80;
|
||||
|
||||
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
|
||||
timer_reordering = 35;
|
||||
|
||||
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
|
||||
timer_status_prohibit = 0;
|
||||
|
||||
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
|
||||
poll_pdu = 4;
|
||||
|
||||
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
|
||||
poll_byte = 99999;
|
||||
|
||||
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
|
||||
max_retx_threshold = 4;
|
||||
}
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
|
||||
////////// MME parameters:
|
||||
mme_ip_address = ( { ipv4 = "10.193.4.249";
|
||||
ipv6 = "";
|
||||
active = "yes";
|
||||
preference = "ipv4";
|
||||
}
|
||||
);
|
||||
|
||||
enable_measurement_reports = "no";
|
||||
|
||||
///X2
|
||||
enable_x2 = "no";
|
||||
t_reloc_prep = 1000; /* unit: millisecond */
|
||||
tx2_reloc_overall = 2000; /* unit: millisecond */
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
ENB_INTERFACE_NAME_FOR_S1_MME = "eth1";
|
||||
ENB_IPV4_ADDRESS_FOR_S1_MME = "10.193.4.248";
|
||||
ENB_INTERFACE_NAME_FOR_S1U = "eth1";
|
||||
ENB_IPV4_ADDRESS_FOR_S1U = "10.193.4.248";
|
||||
ENB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
ENB_IPV4_ADDRESS_FOR_X2C = "10.193.4.248";
|
||||
ENB_PORT_FOR_X2C = 36422; # Spec 36422
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
phy_test_mode = 0;
|
||||
puSch10xSnr = 160;
|
||||
puCch10xSnr = 160;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "yes"
|
||||
nb_tx = 1
|
||||
nb_rx = 1
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [7];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 116;
|
||||
eNB_instances = [0];
|
||||
sdr_addrs = "type=x300";
|
||||
}
|
||||
);
|
||||
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
|
||||
parallel_config = "PARALLEL_SINGLE_THREAD";
|
||||
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
|
||||
worker_config = "WORKER_DISABLE";
|
||||
}
|
||||
);
|
||||
|
||||
NETWORK_CONTROLLER :
|
||||
{
|
||||
FLEXRAN_ENABLED = "no";
|
||||
FLEXRAN_INTERFACE_NAME = "lo";
|
||||
FLEXRAN_IPV4_ADDRESS = "127.0.0.1";
|
||||
FLEXRAN_PORT = 2210;
|
||||
FLEXRAN_CACHE = "/mnt/oai_agent_cache";
|
||||
FLEXRAN_AWAIT_RECONF = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level ="warn";
|
||||
global_log_verbosity ="high";
|
||||
hw_log_level ="warn";
|
||||
hw_log_verbosity ="high";
|
||||
phy_log_level ="warn";
|
||||
phy_log_verbosity ="high";
|
||||
mac_log_level ="warn";
|
||||
mac_log_verbosity ="high";
|
||||
rlc_log_level ="warn";
|
||||
rlc_log_verbosity ="high";
|
||||
pdcp_log_level ="warn";
|
||||
pdcp_log_verbosity ="high";
|
||||
rrc_log_level ="warn";
|
||||
rrc_log_verbosity ="high";
|
||||
};
|
||||
|
||||
@@ -340,7 +340,6 @@ add_boolean_option(DEBUG_MAC_INTERFACE False "print MAC-RLC PDU exchange to stdo
|
||||
add_boolean_option(TRACE_RLC_PAYLOAD False "print RLC PDU to stdout") # if true, make sure that global and PDCP log levels are trace
|
||||
add_boolean_option(PRINT_STATS False "This adds the possibility to see the status")
|
||||
add_boolean_option(T_TRACER True "Activate the T tracer, a debugging/monitoring framework" )
|
||||
add_boolean_option(LATSEQ False "Active Latency Sequence tools")
|
||||
add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs")
|
||||
add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace")
|
||||
add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace")
|
||||
@@ -1203,7 +1202,6 @@ add_library(UTIL
|
||||
${OPENAIR2_DIR}/UTIL/LISTS/list2.c
|
||||
${OPENAIR_DIR}/common/utils/LOG/log.c
|
||||
${OPENAIR_DIR}/common/utils/LOG/vcd_signal_dumper.c
|
||||
${OPENAIR_DIR}/common/utils/LATSEQ/latseq.c
|
||||
${OPENAIR2_DIR}/UTIL/MATH/oml.c
|
||||
${OPENAIR2_DIR}/UTIL/OPT/probe.c
|
||||
${OPENAIR_DIR}/common/utils/threadPool/thread-pool.c
|
||||
@@ -1723,7 +1721,6 @@ set(PHY_MEX_UE
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/signal_energy.c
|
||||
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ue_measurements.c
|
||||
${OPENAIR_DIR}/common/utils/LOG/log.c
|
||||
${OPENAIR_DIR}/common/utils/LATSEQ/latseq.c
|
||||
${OPENAIR_DIR}/common/utils/T/T.c
|
||||
${OPENAIR_DIR}/common/utils/T/local_tracer.c
|
||||
)
|
||||
@@ -3185,3 +3182,4 @@ ADD_CUSTOM_TARGET(oarf
|
||||
|
||||
include (${OPENAIR_DIR}/common/utils/telnetsrv/telnetsrv_CMakeLists.txt)
|
||||
include(${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt)
|
||||
include (${OPENAIR_DIR}/common/utils/websrv/websrv_CMakeLists.txt)
|
||||
|
||||
@@ -58,7 +58,7 @@ CMAKE_CMD="$CMAKE"
|
||||
NOAVX512="False"
|
||||
BUILD_ECLIPSE=0
|
||||
NR="False"
|
||||
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope"
|
||||
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope websrv"
|
||||
RU=0
|
||||
CMAKE_C_FLAGS=()
|
||||
CMAKE_CXX_FLAGS=()
|
||||
@@ -395,10 +395,6 @@ function main() {
|
||||
CMAKE_CMD="$CMAKE_CMD -DT_TRACER=False"
|
||||
echo_info "Disabling the T tracer"
|
||||
shift 1;;
|
||||
--enable-latseq)
|
||||
CMAKE_CMD="$CMAKE_CMD -DLATSEQ=True"
|
||||
echo info "Enabling Latency Sequence measures"
|
||||
shift 1;;
|
||||
--disable-hardware-dependency)
|
||||
echo_info "Disabling hardware dependency for compiling software"
|
||||
DISABLE_HARDWARE_DEPENDENCY="True"
|
||||
|
||||
@@ -197,8 +197,8 @@ check_warnings() {
|
||||
#argument:
|
||||
# $1: log file
|
||||
check_errors() {
|
||||
#we look for 'warning:' in the compilation log file
|
||||
error_count=`grep "error:" "$1" | wc -l`
|
||||
#we look for 'error:' in the compilation log file
|
||||
error_count=`grep -c "error:" "$1"`
|
||||
if [ $error_count -gt 0 ]; then
|
||||
echo_error "ERROR: $error_count error. See $1"
|
||||
fi
|
||||
@@ -217,7 +217,6 @@ compilations() {
|
||||
if [ "$MAKE_CMD" != "" ]; then
|
||||
$MAKE_CMD $2
|
||||
else
|
||||
|
||||
if [ "$VERBOSE_COMPILE" == "1" ]; then
|
||||
$COV_SCAN_PREFIX make -j`nproc` $2 VERBOSE=$VERBOSE_COMPILE
|
||||
else
|
||||
|
||||
@@ -88,6 +88,8 @@ int processoption(paramdef_t *cfgoptions, char *value) {
|
||||
config_check_valptr(cfgoptions, cfgoptions->strptr, strlen(tmpval)+1);
|
||||
sprintf(*(cfgoptions->strptr), "%s",tmpval);
|
||||
} else {
|
||||
AssertFatal( ( strlen(*(cfgoptions->strptr)) < cfgoptions->numelt), "[CONFIG] Error: %s too long, %s value cannot exceed %i bytes\n",
|
||||
cfgoptions->optname,tmpval, cfgoptions->numelt) ;
|
||||
sprintf( (char *)(cfgoptions->strptr), "%s",tmpval);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,13 +88,32 @@ int load_config_sharedlib(configmodule_interface_t *cfgptr) {
|
||||
st = -1;
|
||||
}
|
||||
|
||||
if ( cfgptr->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
sprintf (fname,"config_%s_set",cfgptr->cfgmode);
|
||||
cfgptr->set = dlsym(lib_handle,fname);
|
||||
|
||||
if (cfgptr->set == NULL ) {
|
||||
printf("[CONFIG] %s %d no function %s for config mode %s\n",
|
||||
__FILE__, __LINE__,fname, cfgptr->cfgmode);
|
||||
st = -1;
|
||||
}
|
||||
sprintf (fname,"config_%s_write_parsedcfg",cfgptr->cfgmode);
|
||||
cfgptr->write_parsedcfg = dlsym(lib_handle,fname);
|
||||
|
||||
if (cfgptr->write_parsedcfg == NULL ) {
|
||||
printf("[CONFIG] %s %d no function %s for config mode %s\n",
|
||||
__FILE__, __LINE__,fname, cfgptr->cfgmode);
|
||||
}
|
||||
}
|
||||
|
||||
sprintf (fname,"config_%s_end",cfgptr->cfgmode);
|
||||
cfgptr->end = dlsym(lib_handle,fname);
|
||||
|
||||
if (cfgptr->getlist == NULL ) {
|
||||
if (cfgptr->end == NULL ) {
|
||||
printf("[CONFIG] %s %d no function %s for config mode %s\n",
|
||||
__FILE__, __LINE__,fname, cfgptr->cfgmode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return st;
|
||||
@@ -186,6 +205,7 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
uint32_t initflags)
|
||||
{
|
||||
char *cfgparam=NULL;
|
||||
|
||||
char *modeparams=NULL;
|
||||
char *cfgmode=NULL;
|
||||
char *strtokctx=NULL;
|
||||
@@ -193,7 +213,8 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
uint32_t tmpflags=0;
|
||||
int i;
|
||||
int OoptIdx=-1;
|
||||
|
||||
int OWoptIdx=-1;
|
||||
|
||||
printf("CMDLINE: ");
|
||||
for (int i=0; i<argc; i++)
|
||||
printf("\"%s\" ", argv[i]);
|
||||
@@ -208,7 +229,11 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
cfgparam = argv[i+1];
|
||||
OoptIdx=i;
|
||||
}
|
||||
|
||||
|
||||
char *OWopt = strstr(argv[i],"OW");
|
||||
if ( OWopt == argv[i]+2) {
|
||||
OWoptIdx=i;
|
||||
}
|
||||
if ( strstr(argv[i], "help_config") != NULL ) {
|
||||
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params),CONFIG_SECTIONNAME);
|
||||
exit(0);
|
||||
@@ -258,6 +283,11 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
/* argv[0] is the exec name, always Ok */
|
||||
cfgptr->argv_info[0] |= CONFIG_CMDLINEOPT_PROCESSED;
|
||||
|
||||
/* When reuested _(_--OW or rtflag is 5), a file with config parameters, as defined after all processing, will be created */
|
||||
if (OWoptIdx >= 0) {
|
||||
cfgptr->argv_info[OWoptIdx] |= CONFIG_CMDLINEOPT_PROCESSED;
|
||||
cfgptr->rtflags |= CONFIG_SAVERUNCFG ;
|
||||
}
|
||||
/* when OoptIdx is >0, -O option has been detected at position OoptIdx
|
||||
* we must memorize arv[OoptIdx is Ok */
|
||||
if (OoptIdx >= 0) {
|
||||
@@ -294,14 +324,18 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
printf("%s ",cfgptr->cfgP[i]);
|
||||
}
|
||||
|
||||
printf(", debug flags: 0x%08x\n",cfgptr->rtflags);
|
||||
|
||||
if (cfgptr->rtflags & CONFIG_PRINTPARAMS) {
|
||||
cfgptr->status = malloc(sizeof(configmodule_status_t));
|
||||
}
|
||||
if (strstr(cfgparam,CONFIG_CMDLINEONLY) == NULL) {
|
||||
i=load_config_sharedlib(cfgptr);
|
||||
|
||||
if (i == 0) {
|
||||
printf("[CONFIG] config module %s loaded\n",cfgmode);
|
||||
Config_Params[CONFIGPARAM_DEBUGFLAGS_IDX].uptr=&(cfgptr->rtflags);
|
||||
int idx = config_paramidx_fromname(Config_Params, CONFIG_PARAMLENGTH(Config_Params), CONFIGP_DEBUGFLAGS);
|
||||
Config_Params[idx].uptr=&(cfgptr->rtflags);
|
||||
idx = config_paramidx_fromname(Config_Params, CONFIG_PARAMLENGTH(Config_Params), CONFIGP_TMPDIR);
|
||||
Config_Params[idx].strptr=&(cfgptr->tmpdir);
|
||||
config_get(Config_Params,CONFIG_PARAMLENGTH(Config_Params), CONFIG_SECTIONNAME );
|
||||
} else {
|
||||
fprintf(stderr,"[CONFIG] %s %d config module \"%s\" couldn't be loaded\n", __FILE__, __LINE__,cfgmode);
|
||||
@@ -313,7 +347,10 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
cfgptr->getlist = config_cmdlineonly_getlist;
|
||||
cfgptr->end = (configmodule_endfunc_t)nooptfunc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
printf("[CONFIG] debug flags: 0x%08x\n",cfgptr->rtflags);
|
||||
|
||||
if (modeparams != NULL) free(modeparams);
|
||||
|
||||
if (cfgmode != NULL) free(cfgmode);
|
||||
@@ -326,10 +363,28 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
return cfgptr;
|
||||
}
|
||||
|
||||
/* Possibly write config file, with parameters which have been read and after command line parsing */
|
||||
void write_parsedcfg(void) {
|
||||
if ( cfgptr->status && (cfgptr->rtflags & CONFIG_SAVERUNCFG)) {
|
||||
printf_params("[CONFIG] Runtime params creation status: %i null values, %i errors, %i empty list or array, %i successfull \n",
|
||||
cfgptr->status->num_err_nullvalue,
|
||||
cfgptr->status->num_err_write,
|
||||
cfgptr->status->emptyla,
|
||||
cfgptr->status->num_write);
|
||||
|
||||
}
|
||||
if (cfgptr != NULL) {
|
||||
if (cfgptr->write_parsedcfg != NULL) {
|
||||
printf ("[CONFIG] calling config module write_parsedcfg function...\n");
|
||||
cfgptr->write_parsedcfg();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free memory allocated when reading parameters */
|
||||
/* config module could be initialized again after this call */
|
||||
void end_configmodule(void) {
|
||||
write_parsedcfg();
|
||||
if (cfgptr != NULL) {
|
||||
if (cfgptr->end != NULL) {
|
||||
printf ("[CONFIG] calling config module end function...\n");
|
||||
@@ -355,7 +410,10 @@ void end_configmodule(void) {
|
||||
void free_configmodule(void) {
|
||||
if (cfgptr != NULL) {
|
||||
end_configmodule();
|
||||
|
||||
if( cfgptr->status != NULL) {
|
||||
free(cfgptr->status->debug_cfgname);
|
||||
free(cfgptr->status);
|
||||
}
|
||||
if( cfgptr->cfgmode != NULL) free(cfgptr->cfgmode);
|
||||
|
||||
printf ("[CONFIG] free %i config parameter pointers\n",cfgptr->num_cfgP);
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#define CONFIG_DEBUGPTR (1<<1) // print memory allocation/free debug messages
|
||||
#define CONFIG_DEBUGCMDLINE (1<<2) // print command line processing messages
|
||||
#define CONFIG_NOABORTONCHKF (1<<4) // disable abort execution when parameter checking function fails
|
||||
#define CONFIG_SAVERUNCFG (1<<5) // create config file with running values, as after cfg file + command line processing
|
||||
#define CONFIG_NOEXITONHELP (1<<19) // do not exit after printing help
|
||||
#define CONFIG_HELP (1<<20) // print help message
|
||||
#define CONFIG_ABORT (1<<21) // config failed,abort execution
|
||||
@@ -61,7 +62,20 @@
|
||||
typedef int(*configmodule_initfunc_t)(char *cfgP[],int numP);
|
||||
typedef int(*configmodule_getfunc_t)(paramdef_t *,int numparams, char *prefix);
|
||||
typedef int(*configmodule_getlistfunc_t)(paramlist_def_t *, paramdef_t *,int numparams, char *prefix);
|
||||
typedef int(*configmodule_setfunc_t)(paramdef_t *cfgoptions, int numoptions, char *prefix );
|
||||
typedef void(*configmodule_endfunc_t)(void);
|
||||
typedef struct configmodule_status {
|
||||
int num_paramgroups;
|
||||
char ** paramgroups_names;
|
||||
int num_err_nullvalue;
|
||||
int emptyla;
|
||||
int num_err_read;
|
||||
int num_err_write;
|
||||
int num_read;
|
||||
int num_write;
|
||||
char *debug_cfgname;
|
||||
}configmodule_status_t;
|
||||
|
||||
typedef struct configmodule_interface {
|
||||
int argc;
|
||||
char **argv;
|
||||
@@ -72,11 +86,15 @@ typedef struct configmodule_interface {
|
||||
configmodule_initfunc_t init;
|
||||
configmodule_getfunc_t get;
|
||||
configmodule_getlistfunc_t getlist;
|
||||
configmodule_setfunc_t set;
|
||||
configmodule_endfunc_t end;
|
||||
configmodule_endfunc_t write_parsedcfg;
|
||||
uint32_t numptrs;
|
||||
uint32_t rtflags;
|
||||
char *ptrs[CONFIG_MAX_ALLOCATEDPTRS];
|
||||
bool ptrsAllocated[CONFIG_MAX_ALLOCATEDPTRS];
|
||||
char *tmpdir;
|
||||
configmodule_status_t *status; // allocated in debug mode only
|
||||
} configmodule_interface_t;
|
||||
|
||||
#ifdef CONFIG_LOADCONFIG_MAIN
|
||||
@@ -89,16 +107,19 @@ static char config_helpstr [] = "\n lte-softmodem -O [config mode]<:dbgl[debugfl
|
||||
incp parameter can be used to define the include path used for config files (@include directive)\n \
|
||||
defaults is set to the path of the main config file.\n";
|
||||
|
||||
#define CONFIG_SECTIONNAME "config"
|
||||
#define CONFIGPARAM_DEBUGFLAGS_IDX 0
|
||||
#define CONFIG_HELP_TMPDIR "<Repository to create temporary file>"
|
||||
|
||||
#define CONFIG_SECTIONNAME "config"
|
||||
#define CONFIGP_DEBUGFLAGS "debugflags"
|
||||
#define CONFIGP_TMPDIR "tmpdir"
|
||||
|
||||
static paramdef_t Config_Params[] = {
|
||||
/*-----------------------------------------------------------------------------------------------------------------------*/
|
||||
/* config parameters for config module */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-----------------------------------------------------------------------------------------------------------------------*/
|
||||
{"debugflags", config_helpstr, 0, uptr:NULL, defintval:0, TYPE_MASK, 0},
|
||||
/*--------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* config parameters for config module */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*--------------------------------------------------------------------------------------------------------------------------*/
|
||||
{CONFIGP_DEBUGFLAGS, config_helpstr, 0, uptr:NULL, defintval:0, TYPE_MASK, 0},
|
||||
{CONFIGP_TMPDIR, CONFIG_HELP_TMPDIR,PARAMFLAG_NOFREE, strptr:NULL, defstrval:"/tmp" ,TYPE_STRING, 0},
|
||||
};
|
||||
|
||||
#else
|
||||
@@ -113,6 +134,7 @@ extern configmodule_interface_t *cfgptr;
|
||||
#define CONFIG_ENABLECMDLINEONLY (1<<1)
|
||||
extern configmodule_interface_t *load_configmodule(int argc, char **argv, uint32_t initflags);
|
||||
extern void end_configmodule(void);
|
||||
extern void write_parsedcfg(void);
|
||||
#define CONFIG_PRINTF_ERROR(f, x... ) if (isLogInitDone ()) { LOG_E(ENB_APP,f,x);} else {printf(f,x);}; if ( !CONFIG_ISFLAGSET(CONFIG_NOABORTONCHKF) ) exit_fun("exit because configuration failed\n");
|
||||
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#define PARAMFLAG_NOFREE (1 << 3) // don't free parameter in end function
|
||||
#define PARAMFLAG_BOOL (1 << 4) // integer param can be 0 or 1
|
||||
#define PARAMFLAG_CMDLINE_NOPREFIXENABLED (1 << 5) // on the command line, allow a parameter to be specified without the prefix
|
||||
#define PARAMFLAG_CMDLINEONLY (1 << 6) // this parameter cannot be specified in config file
|
||||
|
||||
/* Flags used by config modules to return info to calling modules and/or to for internal usage*/
|
||||
#define PARAMFLAG_MALLOCINCONFIG (1 << 15) // parameter allocated in config module
|
||||
|
||||
@@ -237,6 +237,9 @@ int config_get(paramdef_t *params, int numparams, char *prefix) {
|
||||
|
||||
if (ret >= 0) {
|
||||
config_process_cmdline(params, numparams, prefix);
|
||||
if ( cfgif->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
config_get_if()->set(params, numparams, prefix);
|
||||
}
|
||||
config_execcheck(params, numparams, prefix);
|
||||
}
|
||||
|
||||
@@ -271,9 +274,11 @@ int config_getlist(paramlist_def_t *ParamList, paramdef_t *params, int numparams
|
||||
char cfgpath[MAX_OPTNAME_SIZE*2 + 6]; /* prefix.listname.[listindex] */
|
||||
|
||||
for (int i = 0; i < ParamList->numelt; ++i) {
|
||||
// TODO config_process_cmdline?
|
||||
sprintf(cfgpath, "%s.[%i]", newprefix, i);
|
||||
config_process_cmdline(ParamList->paramarray[i],numparams,cfgpath);
|
||||
if ( config_get_if()->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
config_get_if()->set(ParamList->paramarray[i], numparams,cfgpath );
|
||||
}
|
||||
config_execcheck(ParamList->paramarray[i], numparams, cfgpath);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,11 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "config_libconfig.h"
|
||||
#include "config_libconfig_private.h"
|
||||
@@ -87,8 +90,222 @@ int read_intarray(paramdef_t *cfgoptions,config_setting_t *setting, char *cfgpat
|
||||
|
||||
return cfgoptions->numelt;
|
||||
}
|
||||
int config_libconfig_setparams(paramdef_t *cfgoptions, int numoptions, config_setting_t * asetting, char * prefix) {
|
||||
int status;
|
||||
int errors=0;
|
||||
int notused=0;
|
||||
int emptyla=0;
|
||||
#define LIBCONFIG_NOTUSED_PARAMS "Not used? (NULL value ptr)"
|
||||
char *secprefix=(prefix==NULL)?"":prefix;
|
||||
|
||||
for(int i=0; i<numoptions; i++) {
|
||||
if (cfgoptions[i].paramflags & PARAMFLAG_CMDLINEONLY) {
|
||||
continue;
|
||||
printf_params("[LIBCONFIG] setting %s.%s skipped (command line only) \n",secprefix,cfgoptions[i].optname);
|
||||
}
|
||||
status=CONFIG_FALSE;
|
||||
config_setting_t * psetting;
|
||||
char *spath=malloc(((prefix==NULL)?0:strlen(prefix))+strlen(cfgoptions[i].optname)+10);
|
||||
sprintf(spath,"%s%s%s",secprefix, (prefix==NULL)?"":".", cfgoptions[i].optname);
|
||||
psetting = config_lookup(&(libconfig_privdata.runtcfg),spath);
|
||||
free(spath);
|
||||
if (psetting != NULL) {
|
||||
printf_params("[LIBCONFIG] setting %s.%s already created \n",secprefix,cfgoptions[i].optname);
|
||||
continue;
|
||||
}
|
||||
switch(cfgoptions[i].type) {
|
||||
case TYPE_STRING:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_STRING);
|
||||
if (psetting!= NULL) {
|
||||
char *value;
|
||||
if (cfgoptions[i].strptr == NULL) {
|
||||
notused++;
|
||||
value=LIBCONFIG_NOTUSED_PARAMS;
|
||||
} else {
|
||||
if (cfgoptions[i].numelt == 0 ) {
|
||||
value = *(cfgoptions[i].strptr);
|
||||
} else {
|
||||
value = (char *)(cfgoptions[i].strptr);
|
||||
}
|
||||
}
|
||||
status=config_setting_set_string(psetting, value);
|
||||
}
|
||||
break;
|
||||
case TYPE_STRINGLIST:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_LIST);
|
||||
if (psetting!= NULL)
|
||||
{
|
||||
if(cfgoptions[i].numelt <= 0) {
|
||||
emptyla++;
|
||||
printf_params("[LIBCONFIG], no element in list %s\n",cfgoptions[i].optname);
|
||||
status=CONFIG_TRUE;
|
||||
}
|
||||
for (int j=0; j<cfgoptions[i].numelt ; j++) {
|
||||
config_setting_t *elemsetting=config_setting_set_string_elem(psetting, -1,cfgoptions[i].strptr[j] );
|
||||
if (elemsetting == NULL) {
|
||||
fprintf(stderr,"[LIBCONFIG] Error: Creating list %s element %i value %s\n",cfgoptions[i].optname,j,cfgoptions[i].strptr[j]);
|
||||
break;
|
||||
} else
|
||||
status=CONFIG_TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_UINT8:
|
||||
case TYPE_INT8:
|
||||
case TYPE_UINT16:
|
||||
case TYPE_INT16:
|
||||
case TYPE_UINT32:
|
||||
case TYPE_INT32:
|
||||
case TYPE_MASK:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_INT);
|
||||
if (psetting!= NULL)
|
||||
status=config_setting_set_int(psetting, (int)*(cfgoptions[i].iptr) );
|
||||
break;
|
||||
|
||||
case TYPE_UINT64:
|
||||
case TYPE_INT64:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_INT64);
|
||||
if (psetting!= NULL)
|
||||
status=config_setting_set_int64(psetting, (int64_t)*(cfgoptions[i].i64ptr) );
|
||||
break;
|
||||
|
||||
case TYPE_UINTARRAY:
|
||||
case TYPE_INTARRAY:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_ARRAY);
|
||||
if (psetting!= NULL) {
|
||||
if(cfgoptions[i].numelt <= 0) {
|
||||
emptyla++;
|
||||
printf_params("[LIBCONFIG], no element in array %s.%s\n",secprefix,cfgoptions[i].optname);
|
||||
status=CONFIG_TRUE;
|
||||
}
|
||||
for (int j=0; j<cfgoptions[i].numelt ; j++) {
|
||||
config_setting_t *elemsetting=config_setting_set_int_elem(psetting, -1,(int)(cfgoptions[i].iptr[j]) );
|
||||
if (elemsetting == NULL) {
|
||||
fprintf(stderr,"[LIBCONFIG] Error: Creating array %s.%s, at index %i value %i\n",secprefix,cfgoptions[i].optname,j,(int)(cfgoptions[i].iptr[j]));
|
||||
break;
|
||||
} else
|
||||
status=CONFIG_TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_DOUBLE:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_FLOAT);
|
||||
if (psetting!= NULL)
|
||||
status=config_setting_set_float(psetting, (double)*(cfgoptions[i].dblptr) );
|
||||
break;
|
||||
|
||||
case TYPE_IPV4ADDR:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_STRING);
|
||||
if (psetting!= NULL) {
|
||||
char ipstr[INET_ADDRSTRLEN];
|
||||
if (inet_ntop(AF_INET, cfgoptions[i].uptr, ipstr, INET_ADDRSTRLEN) == NULL) {
|
||||
notused++;
|
||||
sprintf(ipstr,"undef");
|
||||
} else {
|
||||
status=config_setting_set_string(psetting, ipstr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LIST:
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,"[LIBCONFIG] %s.%s type %i not supported\n",secprefix,cfgoptions[i].optname ,cfgoptions[i].type);
|
||||
status=CONFIG_FALSE;
|
||||
break;
|
||||
} /* switch on param type */
|
||||
if (status != CONFIG_TRUE) {
|
||||
errors++;
|
||||
fprintf(stderr,"[LIBCONFIG] Error creating setting %i: %s.%s type %i\n",i,secprefix,cfgoptions[i].optname ,cfgoptions[i].type);
|
||||
}
|
||||
}
|
||||
printf_params("[LIBCONFIG], in group \"%s\" %i settings \n",secprefix,numoptions);
|
||||
if (notused > 0)
|
||||
printf_params("[LIBCONFIG], ..... %i settings with NULL value pointer\n",notused);
|
||||
if (errors >0)
|
||||
fprintf(stderr,"[LIBCONFIG] .....%i settings creation errors \n",errors);
|
||||
if (emptyla >0)
|
||||
fprintf(stderr,"[LIBCONFIG] .....%i empty lists or arrays settings \n",emptyla);
|
||||
|
||||
if ( cfgptr->status ) {
|
||||
cfgptr->status->num_err_nullvalue += notused;
|
||||
cfgptr->status->num_err_write += errors;
|
||||
cfgptr->status->num_write += numoptions;
|
||||
cfgptr->status->emptyla += emptyla;
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
int config_libconfig_set(paramdef_t *cfgoptions, int numoptions, char *prefix ) {
|
||||
char *tokctx1=NULL;
|
||||
int listidx=-1;
|
||||
char *prefixbck=NULL;
|
||||
char *prefix_elem1=NULL;
|
||||
config_setting_t * asetting = config_root_setting (&(libconfig_privdata.runtcfg));
|
||||
if (prefix != NULL) {
|
||||
prefixbck=strdup(prefix);
|
||||
prefix_elem1 = strtok_r(prefixbck, ".", &tokctx1);
|
||||
}
|
||||
printf_params("[LIBCONFIG], processing prefix %s\n",(prefix==NULL)?"NULL":prefix);
|
||||
|
||||
/* parse the prefix , possibly creating groups, lists and list elements */
|
||||
while (prefix_elem1 != NULL) {
|
||||
int n1=strlen(prefix_elem1);
|
||||
char *prefix_elem2 = prefix_elem1+n1+1 ;
|
||||
printf_params("[LIBCONFIG], processing elem1 %s elem2 %s\n",prefix_elem1,prefix_elem2);
|
||||
/* prefix (the path to the parameter name) may contain groups and elements from a list, which are specified with [] */
|
||||
if (prefix_elem2[0] != '[') { // not a list
|
||||
|
||||
config_setting_t *tmpset = config_setting_lookup(asetting,prefix_elem1);
|
||||
if (tmpset == NULL)
|
||||
asetting = config_setting_add (asetting, prefix_elem1, CONFIG_TYPE_GROUP);
|
||||
else
|
||||
asetting = tmpset;
|
||||
printf_params("[LIBCONFIG], creating or looking for group %s: %s\n",prefix_elem1,(asetting==NULL)?"NOK":"OK");
|
||||
} else { // a list
|
||||
listidx=(int)strtol(prefix_elem2+1,NULL,10);
|
||||
if (errno == EINVAL || errno == ERANGE) {
|
||||
printf_params("[LIBCONFIG], Error %s looking for list index in %s \n",strerror(errno), prefix_elem2);
|
||||
break;
|
||||
}
|
||||
config_setting_t *tmpset = config_setting_lookup(asetting,prefix_elem1);
|
||||
if (tmpset == NULL)
|
||||
asetting = config_setting_add (asetting, prefix_elem1, CONFIG_TYPE_LIST);
|
||||
else
|
||||
asetting = tmpset;
|
||||
printf_params("[LIBCONFIG], creating or looking for list %s: %s\n",prefix_elem1,(asetting==NULL)?"NOK":"OK");
|
||||
if (asetting != NULL) {
|
||||
tmpset = config_setting_get_elem (asetting, listidx);
|
||||
if (tmpset == NULL)
|
||||
asetting = config_setting_add (asetting, NULL, CONFIG_TYPE_GROUP);
|
||||
else
|
||||
asetting = tmpset;
|
||||
printf_params("[LIBCONFIG], creating or looking for list element %i: %s\n",listidx,(asetting==NULL)?"NOK":"OK");
|
||||
}
|
||||
prefix_elem1 = strtok_r(NULL, ".", &tokctx1); //skip the [x] elements we already took care of it
|
||||
if (prefix_elem1 == NULL) {
|
||||
fprintf(stderr, "[LICONFIG] End of parsing %s \n",prefix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (asetting == NULL) {
|
||||
fprintf(stderr,"[LIBCONFIG] Error creating setting %s %s %i\n",prefix_elem1,prefix_elem2,listidx);
|
||||
}
|
||||
prefix_elem1 = strtok_r(NULL, ".", &tokctx1);
|
||||
}
|
||||
free(prefixbck);
|
||||
if (asetting != NULL) {
|
||||
config_libconfig_setparams(cfgoptions, numoptions,asetting,prefix);
|
||||
printf_params("[LIBCONFIG] %i settings added in group %s\n",numoptions,(prefix==NULL)?"":prefix);
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr,"[LIBCONFIG] Error parsing %s params, skipped...\n",(prefix==NULL)?"":prefix);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int config_libconfig_get(paramdef_t *cfgoptions,int numoptions, char *prefix ) {
|
||||
@@ -376,14 +593,43 @@ int config_libconfig_init(char *cfgP[], int numP) {
|
||||
free(tmppath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* possibly init a libconfig struct for saving really used params */
|
||||
if( cfgptr->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
config_init ( &(libconfig_privdata.runtcfg));
|
||||
// config_set_options (&(libconfig_privdata.runtcfg), CONFIG_OPTION_ALLOW_OVERRIDES, CONFIG_TRUE);
|
||||
}
|
||||
free(tmppath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void config_libconfig_write_parsedcfg(void) {
|
||||
if( cfgptr->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
char *fname=strdup(libconfig_privdata.configfile);
|
||||
int newcfgflen = strlen( libconfig_privdata.configfile) + strlen(cfgptr->tmpdir) + 20;
|
||||
cfgptr->status->debug_cfgname = realloc(cfgptr->status->debug_cfgname, newcfgflen);
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *localtime(&t);
|
||||
snprintf (cfgptr->status->debug_cfgname,newcfgflen, "%s/%s-run%d_%02d_%02d_%02d%02d",cfgptr->tmpdir,basename(fname),
|
||||
tm.tm_year + 1900,tm.tm_mon + 1,tm.tm_mday, tm.tm_hour, tm.tm_min);
|
||||
if ( config_write_file (&(libconfig_privdata.runtcfg) , cfgptr->status->debug_cfgname) != CONFIG_TRUE) {
|
||||
fprintf(stderr,"[LIBCONFIG] %s %d file %s - line %d: %s\n",__FILE__, __LINE__,
|
||||
cfgptr->status->debug_cfgname, config_error_line(&(libconfig_privdata.runtcfg)),
|
||||
config_error_text(&(libconfig_privdata.runtcfg)));
|
||||
} else {
|
||||
printf("[LIBCONFIG] file %s created successfully\n", cfgptr->status->debug_cfgname);
|
||||
}
|
||||
free(fname);
|
||||
} else {
|
||||
printf("[LIBCONFIG] Cannot create config file after parsing: CONFIG_SAVERUNCFG flag not specified\n");
|
||||
}
|
||||
}
|
||||
|
||||
void config_libconfig_end(void ) {
|
||||
config_destroy(&(libconfig_privdata.cfg));
|
||||
|
||||
if( cfgptr->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
config_destroy(&(libconfig_privdata.runtcfg));
|
||||
}
|
||||
if ( libconfig_privdata.configfile != NULL ) {
|
||||
free(libconfig_privdata.configfile);
|
||||
libconfig_privdata.configfile=NULL;
|
||||
|
||||
@@ -40,12 +40,11 @@ extern "C"
|
||||
|
||||
#include "common/config/config_paramdesc.h"
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct libconfig_privatedata {
|
||||
char *configfile;
|
||||
config_t cfg;
|
||||
config_t runtcfg;
|
||||
} libconfig_privatedata_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
# LATency SEQuence analysis extension for OpenAirInterface
|
||||
|
||||
A tool for internal latency analysis in Base Station.
|
||||
Code licenced under BSD-3. See more on https://github.com/Orange-OpenSource/LatSeq
|
||||
Author : Flavien Ronteix--Jacquet (Orange Innovation), Alexandre Ferrieux (Orange Innovation)
|
||||
Email : flavien.ronteixjacquet@orange.com, alexandre.ferrieux@orange.com
|
||||
## Installation
|
||||
|
||||
- Put LatSeq extension source code in OAI code (https://gitlab.eurecom.fr/oai/openairinterface5g). We recommend to put it in the path common/utils/LATSEQ.
|
||||
- In cmake_targets/CMakeLists.txt put `add_boolean_option(LATSEQ True "Active Latency Sequence tools")`. Also add Latseq to compiled source `set(UTIL_SRC... ${OPENAIR_DIR}/common/utils/LATSEQ/latseq.c`
|
||||
- Put test/ in targets/TEST/LATSEQ/
|
||||
- Verify installation of LatSeq with `make` in targets/TEST/LATSEQ
|
||||
|
||||
## Usage
|
||||
|
||||
0) Add init_latseq(appname) and close_latseq() in main Base Station thread at the start and end.
|
||||
1) Add a new LatSeq measure point in the code with
|
||||
#include "common/utils/LATSEQ/latseq.h"
|
||||
#if LATSEQ
|
||||
LATSEQ_P("D pdcp--rlc", "pdcp%d.rlc%d", 0, 1);
|
||||
#endif
|
||||
|
||||
where first argument is the direction, the second the observed segment and the third argument is a string of data_identifier
|
||||
1) Compile OAI code with cmake option LATSEQ at True
|
||||
2) Run scanario for Uplink and Downlink
|
||||
3) Process lseq traces to yield data do statistics with LatSeq tools
|
||||
|
||||
More in docs/Latseq.pdf
|
||||
|
||||
## LatSeq measurement module
|
||||
|
||||
For now, latseq is designed to be the more independant as possible : Means that it does not use oai LOG system (not register by logInit()) and the flag "LATSEQ" disable all lines related to latseq in the code (using #ifdef). In a second time, it could be conceivable to integrate more deeply latseq into oai code.
|
||||
|
||||
latseq_t, global structure for latseq embodied the latseq logging info. log_buffer is a circular buffer with 2 head index, i_write_head and i_read_head. this buffer of latseq_element_t is designed to bo mutex-less.
|
||||
|
||||
LATSEQ_P macro calls log_measure(). The idea is to have a low-footprint at logging explains why log_measure() should do a minimal amount of operations.
|
||||
|
||||
latseq_log_to_file() is the function run in the logger thread. It writes log_elements in the log file.
|
||||
|
||||
LATSEQ_P with direction of D (Downlink) or U (Uplink) observed the passage of a data.
|
||||
LATSEQ_P with direction of I (Information) observed a scalar property at a point of code. e.g. buffer occupancy.
|
||||
|
||||
**We assume that**:
|
||||
- All the point and latseq module run on the same machine (to don't have to synchronize clock of different machines)
|
||||
- Clock give by asm rdtsc is same for all the CPU cores (constant_tsc enabled)
|
||||
|
||||
|
||||
## TOOLS
|
||||
|
||||
Get scripts on https://github.com/Orange-OpenSource/LatSeq/tools
|
||||
|
||||
- rdtsctots : convert rdtsc timestamp to unix timestamp value
|
||||
- latseq_logs : convert lseq log file into useful json file for statistics and visualization
|
||||
- filter_Is.awk : filter contextual informations
|
||||
- lseqj2any : generate waterfall to format gp or svg
|
||||
|
||||
- latseq_checker : verify constitency of Latseq points before compiling
|
||||
- latseq_filter : filter output of latseq_logs
|
||||
- latseq_stats : perform statistic
|
||||
|
||||
### latseq_checker
|
||||
Checker to verify that points LATSEQ_P points are consistent.
|
||||
Verify the number of argument, the emptiness, format...
|
||||
|
||||
ex. ./latseq_checker.sh /home/oai/
|
||||
|
||||
### rdtsctots
|
||||
convert rdtsc value to unix timestamp value
|
||||
|
||||
ex. `./rdtsctots.py trace_raw.lseq > trace.lseq`
|
||||
|
||||
### latseq_logs
|
||||
Proceeds LatSeq logs.
|
||||
A *.lseq is required.
|
||||
By default, builds the latseq_log object.
|
||||
- Reads lseq file given in raw_input
|
||||
- Cleans raw_input to inputs.
|
||||
- Builds points structure and paths possible.
|
||||
- Saves object related to the *.lseq files to a *.plk (pickle)
|
||||
|
||||
**Arguments**:
|
||||
- "-h" : help
|
||||
- "-C" : cleans pickle file associated to the log file and rebuild
|
||||
- "-l" : required lseq file of fingerprints
|
||||
- "-i" : request cleaned input measurements in the case of command line script
|
||||
- "-r" returns the paths present in the log file as json.
|
||||
```
|
||||
{
|
||||
"D": [
|
||||
["ip", "pdcp.in",...],
|
||||
...
|
||||
],
|
||||
"U": ...
|
||||
}
|
||||
``̀
|
||||
|
||||
- "-p" returns points structure as json.
|
||||
Becareful, if journeys has not been rebuilt, then you do not have "duration" attibute which is used for statistics.
|
||||
```
|
||||
{
|
||||
"layer1.point": {
|
||||
"next": [layer2.point2,...],
|
||||
"count": 5,
|
||||
"dir": [0],
|
||||
"duration": {
|
||||
"journeys uid": 0.0115,
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
- "-j" returns journeys structure as json.
|
||||
- Rebuilds journeys with rebuild_packets_journey method
|
||||
- Builds out_journeys
|
||||
```
|
||||
{
|
||||
"uid": 52,
|
||||
"dir": 0,
|
||||
"glob": {
|
||||
"rnti": "54614",...
|
||||
},
|
||||
"set": [[1542, 1592409314.253678, "rlc.rx.am--pdcp.rx"],[...],...], # set of pointer to input entry
|
||||
"set_ids": {
|
||||
"drb": "1",...
|
||||
},
|
||||
"path": 0, # path according to direction and paths obtainable by -p
|
||||
"completed": true,
|
||||
"ts_in": 123.456,
|
||||
"ts_out": 789.012
|
||||
}
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
- "-m" returns metadata of information as list
|
||||
```
|
||||
20200423_143226.191801 rlc.am.txbuf occ1:drb1
|
||||
20200423_143226.191802 rlc.am.txbuf occ2:drb1
|
||||
...
|
||||
20200423_143226.192000 rlc.um.txbuf occ15:drb2
|
||||
```
|
||||
|
||||
- "-o" returns a latseq journey file line by line. redirects output to a file to have a *.lseqj for waterfall generation
|
||||
```
|
||||
#funcId ip pdcp.in pdcp.tx rlc.tx.um rlc.seg.um mac.mux mac.txreq phy.out.proc phy.in.proc mac.demux rlc.rx.um rlc.unseg.um pdcp.rx
|
||||
20200423_143226.191801 D (len64) ip--pdcp.in.gtp uid0.rnti54614.drb1.gsn12
|
||||
20200423_143226.191802 D (len64) pdcp.in--pdcp.tx uid0.rnti54614.drb1.gsn12.psn10
|
||||
20200423_143226.191803 D (len66) pdcp.tx--rlc.tx.um uid0.rnti54614.drb1.psn10.lcid3.rsdu0
|
||||
```
|
||||
|
||||
Requested json are printed in stdout line by line
|
||||
Errors, Warnings, Informations are printed in stderr
|
||||
|
||||
Example of usage:
|
||||
./latseq_logs.py -l ~/latseq.23042020.lseq 2>/dev/null
|
||||
./latseq_logs.py -j -l ~/latseq.23042020.lseq 2>/dev/null
|
||||
./latseq_logs.py -p -l ~/latseq.23042020.lseq 2>/dev/null
|
||||
./latseq_logs.py -o -l ~/latseq.23042020.lseq > 23042020.lseqj 2>/dev/null
|
||||
|
||||
### latseq_filter
|
||||
Applies a filter to a json stream.
|
||||
It uses jq filters.
|
||||
Help website to design jq filter : https://jqplay.org/
|
||||
|
||||
Takes a file with a filter or a filter as string in argument.
|
||||
|
||||
Example of usage:
|
||||
./latseq_filter.sh journeys_downlinks_gsn.lfilter
|
||||
cat journeys_downlinks_gsn.lfilter
|
||||
> select(.["dir"] == 0 and .["set_ids"]["gsn"] == "18")
|
||||
|
||||
### latseq_stats
|
||||
Performs statistics from json. Report json or print in stdout.
|
||||
|
||||
By default, reads on stdin. "-l" *.lseq will try to open a *.json associated.
|
||||
By default, returns a json report on stdout.
|
||||
|
||||
Arguments:
|
||||
- "-f" enables to choose format "json", "csv",...
|
||||
- "-P" prints statistics formated by the latseq_stats module.
|
||||
- "-sj" returns statistics on journeys
|
||||
`̀``
|
||||
{
|
||||
"D": {
|
||||
"size": 34,
|
||||
"min": 0.19598,
|
||||
"max": 1.187086,
|
||||
"mean": 0.788976,
|
||||
"stdev": 0.153623,
|
||||
"quantiles": [0.694859, 0.699043, 0.834942, 0.838041, 0.955701]
|
||||
}
|
||||
`̀``
|
||||
|
||||
- "-sjpp" returns the shares of delay introduced by each point for each journeys by path.
|
||||
```
|
||||
{
|
||||
"U02": { # Uplinks, path 0, point 2
|
||||
"size": 4,
|
||||
"min": 0,
|
||||
"max": 0.7273,
|
||||
"mean": 0.36239999999999994,
|
||||
"stdev": 0.2915949673776967,
|
||||
"quantiles": [
|
||||
0.025005000000000003,
|
||||
0.125025,
|
||||
0.36114999999999997,
|
||||
0.598525,
|
||||
0.7015449999999999
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- "-sp" returns statistics on points
|
||||
```
|
||||
{
|
||||
"pdcp.rx": {
|
||||
"dir": "U",
|
||||
"size": 4,
|
||||
"min": 0.01,
|
||||
"max": 0.02,
|
||||
"mean": 0.015,
|
||||
"stdev": 0.005,
|
||||
"quantiles": [0.012,...] # 5%, 25%, 50%, 75%, 95%
|
||||
},
|
||||
...
|
||||
}
|
||||
`̀``
|
||||
|
||||
- "-djd" returns data journeys' duration
|
||||
`̀``
|
||||
{
|
||||
"00": { # first decimal indicates uplink/downlink followed by the journey unique id
|
||||
"ts": 1587645146.191801,
|
||||
"durations": 0.19598 # in ms
|
||||
},
|
||||
...
|
||||
}
|
||||
`̀``
|
||||
|
||||
Example of usage of the full toolchain for LatSeq Analysis Module
|
||||
./latseq_logs.py -l ~/latseq.simple.lseq -j 2>/dev/null | ./latseq_filter.sh journeys_downlinks_gsn.lfilt | ./latseq_stats.py -sj --print
|
||||
|
||||
### lseqj2any
|
||||
|
||||
generate waterfall
|
||||
|
||||
cat uplink_burst.30102020_203233.lseqj | lseqj2any gp > uplink_burst.gp
|
||||
|
||||
## TEST_LATSEQ
|
||||
in targets/TEST/LATSEQ test_latseq test different part of latseq module
|
||||
- "h" : help menu
|
||||
- "i" : test init and close latseq
|
||||
- "a" : test init, capture 2 fingerprints and close
|
||||
- "t" : same test as "a" but with 2 concurrent threads
|
||||
- "m" : test measurement time to capture 1000000 fingerprints
|
||||
- "n" : test measurement time to capture 1000 fingerprints with 1,2,3,5,10 data identifiers
|
||||
- "w" : test writer speed for a simplified data collector
|
||||
|
||||
@@ -1,284 +0,0 @@
|
||||
/*
|
||||
* Software Name : LatSeq
|
||||
* Version: 1.0
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2020-2021 Orange Labs
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* This software is distributed under the BSD 3-clause,
|
||||
* the text of which is available at https://opensource.org/licenses/BSD-3-Clause
|
||||
* or see the "license.txt" file for more details.
|
||||
*
|
||||
* Author: Flavien Ronteix--Jacquet
|
||||
* Software description: LatSeq measurement part core
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE // required for pthread_setname_np()
|
||||
#include "latseq.h"
|
||||
|
||||
/*--- GLOBALS and EXTERNS ----------------------------------------------------*/
|
||||
|
||||
latseq_t g_latseq;
|
||||
__thread latseq_thread_data_t tls_latseq = {
|
||||
.th_latseq_id = 0
|
||||
}; // need to be a thread local storage variable.
|
||||
pthread_t logger_thread;
|
||||
pthread_t fflusher_thread;
|
||||
//double cpuf; //cpu frequency in MHz -> usec. Should be initialized in main.c
|
||||
extern volatile int oai_exit; //oai is ended. Close latseq
|
||||
|
||||
/*--- UTILS FUNCTIONS --------------------------------------------------------*/
|
||||
|
||||
uint64_t get_cpu_freq_cycles(void)
|
||||
{
|
||||
uint64_t ts = l_rdtsc();
|
||||
sleep(1);
|
||||
return (l_rdtsc() - ts);
|
||||
}
|
||||
|
||||
/*--- MAIN THREAD FUNCTIONS --------------------------------------------------*/
|
||||
|
||||
int init_latseq(const char * appname, uint64_t cpufreq)
|
||||
{
|
||||
// init members
|
||||
g_latseq.is_running = 0;
|
||||
//synchronise time and rdtsc
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
g_latseq.time_zero = (uint64_t)ts.tv_sec * 1000000000LL + (uint64_t)ts.tv_nsec;
|
||||
g_latseq.rdtsc_zero = l_rdtsc(); //check at compile time that constant_tsc is enabled in /proc/cpuinfo
|
||||
if (cpufreq == 0) {
|
||||
g_latseq.cpu_freq = get_cpu_freq_cycles();
|
||||
} else {
|
||||
g_latseq.cpu_freq = cpufreq;
|
||||
}
|
||||
|
||||
// Open traces
|
||||
char time_string[16];
|
||||
strftime(time_string, sizeof (time_string), "%d%m%Y_%H%M%S", localtime(&ts.tv_sec));
|
||||
g_latseq.filelog_name = (char *)malloc(LATSEQ_MAX_STR_SIZE);
|
||||
sprintf(g_latseq.filelog_name, "%s.%s.lseq", appname, time_string);
|
||||
//open logfile
|
||||
g_latseq.outstream = fopen(g_latseq.filelog_name, "w");
|
||||
if (g_latseq.outstream == NULL) {
|
||||
g_latseq.is_running = 0;
|
||||
printf("[LATSEQ] Error at opening log file\n");
|
||||
return -1;
|
||||
}
|
||||
//write header
|
||||
char hdr[] = "# LatSeq packet fingerprints\n# By Alexandre Ferrieux and Flavien Ronteix Jacquet\n# timestamp\tU/D\tsrc--dest\tlen:ctxtId:localId\n";
|
||||
size_t ret = fwrite(hdr, sizeof(char), sizeof(hdr) - 1, g_latseq.outstream);
|
||||
if (ret < 0) {
|
||||
printf("[LATSEQ] Error at opening log file\n");
|
||||
g_latseq.is_running = 0;
|
||||
return -1;
|
||||
}
|
||||
fprintf(g_latseq.outstream, "%ld S rdtsc--gettimeofday %ld.%09ld\n", g_latseq.rdtsc_zero, ts.tv_sec, ts.tv_nsec);
|
||||
fflush(g_latseq.outstream);
|
||||
|
||||
// init registry
|
||||
g_latseq.local_log_buffers.read_ith_thread = 0;
|
||||
g_latseq.local_log_buffers.nb_th = 0;
|
||||
memset(&g_latseq.local_log_buffers.i_read_heads, 0, MAX_NB_THREAD * sizeof(unsigned int));
|
||||
|
||||
// init stat
|
||||
g_latseq.stats.entry_counter = 0;
|
||||
g_latseq.stats.bytes_counter = 0;
|
||||
|
||||
// init latseq_thread_t
|
||||
tls_latseq.th_latseq_id = 0;
|
||||
|
||||
// init logger thread
|
||||
g_latseq.is_running = 1;
|
||||
|
||||
return init_logger_latseq();
|
||||
}
|
||||
|
||||
int init_logger_latseq(void)
|
||||
{
|
||||
// init thread to write buffer to file
|
||||
if(pthread_create(&logger_thread, NULL, (void *) &latseq_log_to_file, NULL) > 0) {
|
||||
printf("[LATSEQ] Error at starting data collector\n");
|
||||
g_latseq.is_running = 0;
|
||||
return -1;
|
||||
}
|
||||
// init thread to flush into file
|
||||
pthread_create(&fflusher_thread, NULL, (void *) &fflush_latseq_periodically, NULL);
|
||||
|
||||
return g_latseq.is_running;
|
||||
}
|
||||
|
||||
void latseq_print_stats(void)
|
||||
{
|
||||
printf("[LATSEQ] === stats ===\n");
|
||||
printf("[LATSEQ] number of entry in log : %d\n", g_latseq.stats.entry_counter);
|
||||
//printf("[LATSEQ] heads positions : %d (Write) : %d (Read)\n", g_latseq.i_write_head, g_latseq.i_read_head);
|
||||
}
|
||||
|
||||
int close_latseq(void)
|
||||
{
|
||||
g_latseq.is_running = 0;
|
||||
//Wait logger finish to write data
|
||||
pthread_join(logger_thread, NULL);
|
||||
//At this point, data_ids and points should be freed by the logger thread
|
||||
free((char*) g_latseq.filelog_name);
|
||||
if (fclose(g_latseq.outstream)){
|
||||
fprintf(stderr, "[LATSEQ] error on closing %s\n", g_latseq.filelog_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--- INSTRUMENTED THREAD FUNCTIONS ------------------------------------------*/
|
||||
|
||||
int init_thread_for_latseq(void)
|
||||
{
|
||||
|
||||
//Init tls_latseq for local thread
|
||||
tls_latseq.i_write_head = 0; //local thread tls_latseq
|
||||
//memset(tls_latseq.log_buffer, 0, sizeof(tls_latseq.log_buffer));
|
||||
|
||||
//Register thread in the registry
|
||||
latseq_registry_t * reg = &g_latseq.local_log_buffers;
|
||||
//Check if space left in registry
|
||||
if (reg->nb_th >= MAX_NB_THREAD) {
|
||||
g_latseq.is_running = 0;
|
||||
fprintf(g_latseq.outstream, "Max instrumented thread MAX_NB_THREAD reached\n");
|
||||
return -1;
|
||||
}
|
||||
reg->tls[reg->nb_th] = &tls_latseq;
|
||||
reg->i_read_heads[reg->nb_th] = 0;
|
||||
|
||||
//Give id to the thread
|
||||
reg->nb_th++;
|
||||
tls_latseq.th_latseq_id = reg->nb_th;
|
||||
return 0;
|
||||
//TODO : No destroy function ? What happens when thread is stopped and data had not been written in the log file ?
|
||||
}
|
||||
|
||||
/*--- DATA COLLECTOR THREAD FUNCTIONS ----------------------------------------*/
|
||||
|
||||
static int write_latseq_entry(void)
|
||||
{
|
||||
//reference to latseq_thread_data
|
||||
latseq_thread_data_t * th = g_latseq.local_log_buffers.tls[g_latseq.local_log_buffers.read_ith_thread];
|
||||
//read_head for this thread_data
|
||||
unsigned int * i_read_head = &g_latseq.local_log_buffers.i_read_heads[g_latseq.local_log_buffers.read_ith_thread];
|
||||
//reference to element to write
|
||||
latseq_element_t * e = &th->log_buffer[(*i_read_head)%RING_BUFFER_SIZE];
|
||||
|
||||
char * tmps;
|
||||
//Convert latseq_element to a string
|
||||
tmps = calloc(LATSEQ_MAX_STR_SIZE, sizeof(char));
|
||||
//Write the data identifier, e.g. do the vsprintf() here and not at measure()
|
||||
//We put the first NB_DATA_IDENTIFIERS elements of array, even there are no NB_DATA_IDENTIFIERS element to write. sprintf will get the firsts...
|
||||
sprintf(
|
||||
tmps,
|
||||
e->format,
|
||||
e->data_id[0],
|
||||
e->data_id[1],
|
||||
e->data_id[2],
|
||||
e->data_id[3],
|
||||
e->data_id[4],
|
||||
e->data_id[5],
|
||||
e->data_id[6],
|
||||
e->data_id[7],
|
||||
e->data_id[8],
|
||||
e->data_id[9]);
|
||||
|
||||
// Write into file
|
||||
int ret = fprintf(g_latseq.outstream, "%ld %s %s\n",
|
||||
e->ts,
|
||||
e->point,
|
||||
tmps);
|
||||
|
||||
if (ret < 0) {
|
||||
g_latseq.is_running = 0;
|
||||
fclose(g_latseq.outstream);
|
||||
fprintf(stderr, "[LATSEQ] output log file cannot be written\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#ifdef LATSEQ_DEBUG
|
||||
fprintf(g_latseq.outstream, "# debug %ld.%06ld : log an entry (len %d) for %s\n", etv.tv_sec, etv.tv_usec, ret, e->point);
|
||||
fprintf(g_latseq.outstream, "# info %ld.%06ld : buffer occupancy (%d / %d) for thread which embedded %s\n",etv.tv_sec, etv.tv_usec, OCCUPANCY((*(&th->i_write_head)%RING_BUFFER_SIZE), ((*i_read_head)%RING_BUFFER_SIZE)), RING_BUFFER_SIZE, e->point);
|
||||
#endif
|
||||
|
||||
free(tmps);
|
||||
// cleanup buffer element
|
||||
e->ts = 0;
|
||||
memset(e->data_id, 0, (sizeof(uint32_t) * e->len_id));
|
||||
e->len_id = 0;
|
||||
|
||||
//Update read_head for the current read_ith_thread
|
||||
//Update g_latseq.local_log_buffers.i_read_heads[g_latseq.local_log_buffers.read_ith_thread] head position
|
||||
(*i_read_head)++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void latseq_log_to_file(void)
|
||||
{
|
||||
// pthread config
|
||||
pthread_t thId = pthread_self();
|
||||
//set name
|
||||
pthread_setname_np(thId, "latseq_log_to_file");
|
||||
//set priority
|
||||
int prio_for_policy = 10;
|
||||
pthread_setschedprio(thId, prio_for_policy);
|
||||
|
||||
latseq_registry_t * reg = &g_latseq.local_log_buffers;
|
||||
int items_to_read = 0;
|
||||
|
||||
while (!oai_exit) { // run until oai is stopped
|
||||
if (!g_latseq.is_running) { break; } //running flag is at 0, not running
|
||||
//If no thread registered, continue and wait
|
||||
if (reg->nb_th == 0) { usleep(1000); continue; }
|
||||
//Select a thread to read with read_ith_thread.
|
||||
// Using RR for now, WRR in near future according to occupancy
|
||||
if (reg->read_ith_thread + 1 >= reg->nb_th) {
|
||||
reg->read_ith_thread = 0;
|
||||
} else {
|
||||
reg->read_ith_thread++;
|
||||
}
|
||||
|
||||
//If max occupancy reached for a local buffer
|
||||
if (reg->tls[reg->read_ith_thread]->i_write_head < reg->i_read_heads[reg->read_ith_thread]) {
|
||||
fprintf(g_latseq.outstream, "# Error\tring buffer of thread (%d) reach max occupancy of %d\n", reg->read_ith_thread, RING_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
items_to_read = CHUNK_SIZE_ITEMS;
|
||||
// Write by chunk
|
||||
while (reg->tls[reg->read_ith_thread]->i_write_head > reg->i_read_heads[reg->read_ith_thread] && items_to_read > 0 ) {
|
||||
//printf("[debug] th %d : (%d)w (%d)r : (%d)items_to_read\n", reg->read_ith_thread, reg->tls[reg->read_ith_thread]->i_write_head, reg->i_read_heads[reg->read_ith_thread], items_to_read);
|
||||
items_to_read--;
|
||||
//Write pointed entry into log file
|
||||
g_latseq.stats.bytes_counter += (uint32_t)write_latseq_entry();
|
||||
g_latseq.stats.entry_counter++;
|
||||
}
|
||||
usleep(1);
|
||||
} // while(!oai_exit)
|
||||
|
||||
//Write all remaining data
|
||||
for (uint8_t i = 0; i < reg->nb_th; i++) {
|
||||
reg->read_ith_thread = i;
|
||||
while (reg->tls[reg->read_ith_thread]->i_write_head > reg->i_read_heads[reg->read_ith_thread])
|
||||
{
|
||||
g_latseq.stats.bytes_counter += (uint32_t)write_latseq_entry();
|
||||
g_latseq.stats.entry_counter++;
|
||||
}
|
||||
}
|
||||
//close_latseq(); // function to close latseq properly
|
||||
//exit thread
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void fflush_latseq_periodically(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
while(1){
|
||||
sleep(1);
|
||||
fflush(g_latseq.outstream);
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
fprintf(g_latseq.outstream, "%ld S rdtsc--gettimeofday %ld.%09ld\n", l_rdtsc(), ts.tv_sec, ts.tv_nsec);
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
@@ -1,409 +0,0 @@
|
||||
/*
|
||||
* Software Name : LatSeq
|
||||
* Version: 1.0
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2020-2021 Orange Labs
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* This software is distributed under the BSD 3-clause,
|
||||
* the text of which is available at https://opensource.org/licenses/BSD-3-Clause
|
||||
* or see the "license.txt" file for more details.
|
||||
*
|
||||
* Author: Flavien Ronteix--Jacquet
|
||||
* Software description: LatSeq measurement part core
|
||||
*/
|
||||
|
||||
#ifndef __LATSEQ_H__
|
||||
#define __LATSEQ_H__
|
||||
|
||||
/*--- INCLUDES ---------------------------------------------------------------*/
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <utils.h>
|
||||
|
||||
/*--- DEFINE -----------------------------------------------------------------*/
|
||||
|
||||
#define RING_BUFFER_SIZE 1024 // Number of fingerprints in Ring Buffer
|
||||
#define NB_DATA_IDENTIFIERS 10 // to update according to distinct data identifier used in point
|
||||
#define LATSEQ_MAX_STR_SIZE 128 // Length for filelog_name AND latseq fingerprint string size
|
||||
#define CHUNK_SIZE_ITEMS 16 // Size of chunk of ring buffer to read at data collector. 1 correspoding to full RR, RING_BUFFER_SIZE read all buffer by passage
|
||||
#define MAX_NB_THREAD 32 // Maximum number of instrumented threads expected
|
||||
|
||||
/*--- MACRO ------------------------------------------------------------------*/
|
||||
#define LATSEQ_P3(p, f, i1) do {log_measure1(p, f, (uint32_t)i1); } while(0)
|
||||
#define LATSEQ_P4(p, f, i1, i2) do {log_measure2(p, f, (uint32_t)i1, (uint32_t)i2); } while(0)
|
||||
#define LATSEQ_P5(p, f, i1, i2, i3) do {log_measure3(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3); } while(0)
|
||||
#define LATSEQ_P6(p, f, i1, i2, i3, i4) do {log_measure4(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4);} while(0)
|
||||
#define LATSEQ_P7(p, f, i1, i2, i3, i4, i5) do {log_measure5(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5); } while(0)
|
||||
#define LATSEQ_P8(p, f, i1, i2, i3, i4, i5, i6) do {log_measure6(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6); } while(0)
|
||||
#define LATSEQ_P9(p, f, i1, i2, i3, i4, i5, i6, i7) do {log_measure7(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6, (uint32_t)i7); } while(0)
|
||||
#define LATSEQ_P10(p, f, i1, i2, i3, i4, i5, i6, i7, i8) do {log_measure8(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6, (uint32_t)i7, (uint32_t)i8); } while(0)
|
||||
#define LATSEQ_P11(p, f, i1, i2, i3, i4, i5, i6, i7, i8, i9) do {log_measure9(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6, (uint32_t)i7, (uint32_t)i8, (uint32_t)i9); } while(0)
|
||||
#define LATSEQ_P12(p, f, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10) do {log_measure10(p, f, (uint32_t)i1, (uint32_t)i2, (uint32_t)i3, (uint32_t)i4, (uint32_t)i5, (uint32_t)i6, (uint32_t)i7, (uint32_t)i8, (uint32_t)i9, (uint32_t)i10); } while(0)
|
||||
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,NAME,...) NAME
|
||||
#define LATSEQ_P(...) GET_MACRO(__VA_ARGS__, LATSEQ_P12, LATSEQ_P11, LATSEQ_P10, LATSEQ_P9, LATSEQ_P8, LATSEQ_P7, LATSEQ_P6, LATSEQ_P5, LATSEQ_P4, LATSEQ_P3)(__VA_ARGS__)
|
||||
#define OCCUPANCY(w, r) (w - r)
|
||||
|
||||
/*--- STRUCT -----------------------------------------------------------------*/
|
||||
|
||||
// A latseq element of the buffer
|
||||
typedef struct latseq_element_t {
|
||||
uint64_t ts; // timestamp of the measure
|
||||
const char * point;
|
||||
const char * format;
|
||||
ushort len_id; // Number data identifiers
|
||||
uint32_t data_id[NB_DATA_IDENTIFIERS]; // values for the data identifier. What is the best type ?
|
||||
} latseq_element_t;
|
||||
|
||||
// Statistics structures for latseq
|
||||
typedef struct latseq_stats_t {
|
||||
uint32_t entry_counter;
|
||||
uint32_t bytes_counter;
|
||||
} latseq_stats_t;
|
||||
|
||||
//thread specific data struct
|
||||
typedef struct latseq_thread_data_t {
|
||||
uint8_t th_latseq_id; //Identifier of pthread for registry
|
||||
latseq_element_t log_buffer[RING_BUFFER_SIZE]; //log buffer, structure mutex-less
|
||||
unsigned int i_write_head; // position of writer in the log_buffer (main thread)
|
||||
} latseq_thread_data_t;
|
||||
|
||||
//Registry of pointers to thread-specific struct latseq_data_thread
|
||||
typedef struct latseq_registry_t {
|
||||
uint8_t read_ith_thread;
|
||||
uint8_t nb_th;
|
||||
latseq_thread_data_t * tls[MAX_NB_THREAD];
|
||||
unsigned int i_read_heads[MAX_NB_THREAD]; // position of reader in the ith log buffer (logger thread)
|
||||
} latseq_registry_t;
|
||||
|
||||
// Global structure of LatSeq module
|
||||
typedef struct latseq_t {
|
||||
int is_running; //1 is running, 0 not running
|
||||
char * filelog_name;
|
||||
FILE * outstream; //Output descriptor
|
||||
uint64_t time_zero; // time zero
|
||||
uint64_t rdtsc_zero; //rdtsc zero
|
||||
uint64_t cpu_freq; //cpu frequency
|
||||
latseq_registry_t local_log_buffers; //Register of thread-specific buffers
|
||||
latseq_stats_t stats; // stats of latseq instance
|
||||
} latseq_t;
|
||||
|
||||
/*--- EXTERNS ----------------------------------------------------------------*/
|
||||
|
||||
extern latseq_t g_latseq; // global structure
|
||||
extern __thread latseq_thread_data_t tls_latseq;
|
||||
|
||||
/*--- FUNCTIONS --------------------------------------------------------------*/
|
||||
/** \fn int init_latseq(const char * appname);
|
||||
* \brief init latency sequences module.
|
||||
* \param appname app's name. The output file is appname.date_hour.lseq
|
||||
* \param cpufreq. cpu frequency in cycles.
|
||||
* \return -1 if error 1 otherwise
|
||||
*/
|
||||
int init_latseq(const char * appname, uint64_t cpufreq);
|
||||
|
||||
/** \fn init_logger_to_mem(void);
|
||||
* \brief init thread logger
|
||||
* \return -1 if error 1 otherwise
|
||||
*/
|
||||
int init_logger_latseq(void);
|
||||
|
||||
/** \fn init_thread_for_latseq(void);
|
||||
* \brief init tls_latseq for local oai thread
|
||||
* \return -1 if error, 0 otherwise
|
||||
*/
|
||||
int init_thread_for_latseq(void);
|
||||
|
||||
/** \fn l_rdtsc(void);
|
||||
* \brief rdtsc wrapper
|
||||
* \return time
|
||||
*/
|
||||
static __inline__ uint64_t l_rdtsc(void) {
|
||||
uint32_t a, d;
|
||||
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||
return (((uint64_t)d)<<32) | ((uint64_t)a);
|
||||
}
|
||||
|
||||
/** \fn get_cpu_freq_cycles(void);
|
||||
* \brief Compute CPU clock in a 1 second experiment
|
||||
* \return CPU clock in cycles
|
||||
*/
|
||||
uint64_t get_cpu_freq_cycles(void);
|
||||
|
||||
/*--- MEASUREMENTS -----------------------------------------------------------*/
|
||||
/** \fn void log_measure(const char * point, const char *identifier);
|
||||
* \brief function to log a new measure into buffer.
|
||||
* From 1 to NB_DATA_IDENTIFIERS
|
||||
* \param point name of the measurement point
|
||||
* \param id identifier for the data pointed
|
||||
* \todo measure latency introduced by this function
|
||||
*/
|
||||
static __inline__ void log_measure1(const char * point, const char *fmt, uint32_t i1)
|
||||
{
|
||||
//check if the oai thread is already registered
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
//get reference on new element
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 1;
|
||||
e->data_id[0] = i1;
|
||||
//Update head position
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
static __inline__ void log_measure2(const char * point, const char *fmt, uint32_t i1, uint32_t i2)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 2;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
static __inline__ void log_measure3(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 3;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
e->data_id[2] = i3;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
static __inline__ void log_measure4(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 4;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
e->data_id[2] = i3;
|
||||
e->data_id[3] = i4;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
static __inline__ void log_measure5(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 5;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
e->data_id[2] = i3;
|
||||
e->data_id[3] = i4;
|
||||
e->data_id[4] = i5;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
static __inline__ void log_measure6(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 6;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
e->data_id[2] = i3;
|
||||
e->data_id[3] = i4;
|
||||
e->data_id[4] = i5;
|
||||
e->data_id[5] = i6;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ void log_measure7(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 7;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
e->data_id[2] = i3;
|
||||
e->data_id[3] = i4;
|
||||
e->data_id[4] = i5;
|
||||
e->data_id[5] = i6;
|
||||
e->data_id[6] = i7;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ void log_measure8(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7, uint32_t i8)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 8;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
e->data_id[2] = i3;
|
||||
e->data_id[3] = i4;
|
||||
e->data_id[4] = i5;
|
||||
e->data_id[5] = i6;
|
||||
e->data_id[6] = i7;
|
||||
e->data_id[7] = i8;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ void log_measure9(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7, uint32_t i8, uint32_t i9)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 9;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
e->data_id[2] = i3;
|
||||
e->data_id[3] = i4;
|
||||
e->data_id[4] = i5;
|
||||
e->data_id[5] = i6;
|
||||
e->data_id[6] = i7;
|
||||
e->data_id[7] = i8;
|
||||
e->data_id[8] = i9;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ void log_measure10(const char * point, const char *fmt, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7, uint32_t i8, uint32_t i9, uint32_t i10)
|
||||
{
|
||||
if (tls_latseq.th_latseq_id == 0) {
|
||||
//is not initialized yet
|
||||
if (init_thread_for_latseq()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
latseq_element_t * e = &tls_latseq.log_buffer[tls_latseq.i_write_head%RING_BUFFER_SIZE];
|
||||
e->ts = l_rdtsc();
|
||||
e->point = point;
|
||||
e->format = fmt;
|
||||
e->len_id = 10;
|
||||
e->data_id[0] = i1;
|
||||
e->data_id[1] = i2;
|
||||
e->data_id[2] = i3;
|
||||
e->data_id[3] = i4;
|
||||
e->data_id[4] = i5;
|
||||
e->data_id[5] = i6;
|
||||
e->data_id[6] = i7;
|
||||
e->data_id[7] = i8;
|
||||
e->data_id[8] = i9;
|
||||
e->data_id[9] = i10;
|
||||
tls_latseq.i_write_head++;
|
||||
}
|
||||
|
||||
/** \fn static int write_latseq_entry(void);
|
||||
* \brief private function to write an entry in the log file
|
||||
*/
|
||||
//static int write_latseq_entry(void);
|
||||
|
||||
/** \fn void log_to_file(void);
|
||||
* \brief function to save buffer of logs into a file
|
||||
*/
|
||||
void latseq_log_to_file(void);
|
||||
|
||||
/** \fn void fflush_latseq_periodically(void);
|
||||
* \brief flush periodically into fprintf
|
||||
*/
|
||||
void fflush_latseq_periodically(void);
|
||||
|
||||
/** \fn void latseq_print_stats(void);
|
||||
* \brief print some stats about latseq
|
||||
*/
|
||||
void latseq_print_stats(void);
|
||||
|
||||
/** \fn int close_latseq(void);
|
||||
* \brief finish latseq measurement if a latseq is running
|
||||
* \return 0 if error 1 otherwise
|
||||
*/
|
||||
int close_latseq(void);
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#endif
|
||||
@@ -302,8 +302,8 @@ void log_getconfig(log_t *g_log)
|
||||
|
||||
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_PREDEF_COMPONENTS; i++) {
|
||||
if(g_log->log_component[i].name == NULL) {
|
||||
g_log->log_component[i].name = malloc(16);
|
||||
sprintf((char *)g_log->log_component[i].name,"comp%i?",i);
|
||||
g_log->log_component[i].name = calloc(1,16);
|
||||
snprintf((char *)g_log->log_component[i].name,15,"undefcomp%i",i);
|
||||
logparams_logfile[i].paramflags = PARAMFLAG_DONOTREAD;
|
||||
logparams_level[i].paramflags = PARAMFLAG_DONOTREAD;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ typedef enum hashtable_return_code_e {
|
||||
HASH_TABLE_KEY_ALREADY_EXISTS = 3,
|
||||
HASH_TABLE_BAD_PARAMETER_HASHTABLE = 4,
|
||||
HASH_TABLE_SYSTEM_ERROR = 5,
|
||||
HASH_TABLE_NONE = 6,
|
||||
HASH_TABLE_CODE_MAX
|
||||
} hashtable_rc_t;
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ paramdef_t telnetoptions[] = {
|
||||
{"loopdelay", "<loop command delay (ms)>\n", 0, uptr:&(telnetparams.loopdelay), defuintval:5000, TYPE_UINT, 0 },
|
||||
{"histfile", "<history file name>\n", PARAMFLAG_NOFREE, strptr:&(telnetparams.histfile), defstrval:"oaitelnet.history", TYPE_STRING, 0 },
|
||||
{"histsize", "<history sizes>\n", 0, iptr:&(telnetparams.histsize), defuintval:50, TYPE_INT, 0 },
|
||||
{"logfile", "log file hen redirecting", PARAMFLAG_NOFREE, strptr:&(telnetparams.logfile), defstrval:"oaisoftmodem.log", TYPE_STRING, 0 },
|
||||
{"phypbsize", "<phy dump buff size (bytes)>\n",0, uptr:&(telnetparams.phyprntbuff_size),defuintval:65000, TYPE_UINT, 0 },
|
||||
{TELNETSRV_OPTNAME_STATICMOD, "<static modules selection>\n", 0, strlistptr:NULL, defstrlistval:telnet_defstatmod,TYPE_STRINGLIST,(sizeof(telnet_defstatmod)/sizeof(char *))},
|
||||
{TELNETSRV_OPTNAME_SHRMOD, "<dynamic modules selection>\n", 0, strlistptr:NULL, defstrlistval:NULL,TYPE_STRINGLIST,0 }
|
||||
@@ -90,25 +91,31 @@ int get_phybsize(void) {
|
||||
};
|
||||
int add_telnetcmd(char *modulename,telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd );
|
||||
int setoutput(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
int wsetoutput(char *buff, int debug, telnet_printfunc_t prnt, ... );
|
||||
int setparam(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
int wsetparam(char *buff, int debug, telnet_printfunc_t prnt, ... );
|
||||
int history_cmd(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
|
||||
|
||||
telnetshell_vardef_t telnet_vardef[] = {
|
||||
{"debug",TELNET_VARTYPE_INT32,&telnetparams.telnetdbg},
|
||||
{"prio",TELNET_VARTYPE_INT32,&telnetparams.priority},
|
||||
{"loopc",TELNET_VARTYPE_INT32,&telnetparams.loopcount},
|
||||
{"loopd",TELNET_VARTYPE_INT32,&telnetparams.loopdelay},
|
||||
{"phypb",TELNET_VARTYPE_INT32,&telnetparams.phyprntbuff_size},
|
||||
{"hsize",TELNET_VARTYPE_INT32,&telnetparams.histsize},
|
||||
{"hfile",TELNET_VARTYPE_STRING,&telnetparams.histfile},
|
||||
{"",0,NULL}
|
||||
{"debug", TELNET_VARTYPE_INT32,0,&telnetparams.telnetdbg},
|
||||
{"prio", TELNET_VARTYPE_INT32,0,&telnetparams.priority},
|
||||
{"loopc", TELNET_VARTYPE_INT32,0,&telnetparams.loopcount},
|
||||
{"loopd", TELNET_VARTYPE_INT32,0,&telnetparams.loopdelay},
|
||||
{"phypb", TELNET_VARTYPE_INT32,0,&telnetparams.phyprntbuff_size},
|
||||
{"hsize", TELNET_VARTYPE_INT32,0,&telnetparams.histsize},
|
||||
{"hfile", TELNET_VARTYPE_STRING,TELNET_CHECKVAL_RDONLY,&telnetparams.histfile},
|
||||
{"logfile",TELNET_VARTYPE_STRING,0,&telnetparams.logfile},
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
|
||||
telnetshell_cmddef_t telnet_cmdarray[] = {
|
||||
{"redirlog","[here,file,off]",setoutput},
|
||||
{"param","[prio]",setparam},
|
||||
{"history","[list,reset]",history_cmd},
|
||||
{"","",NULL},
|
||||
{"redirlog","[here,file,off]",setoutput,{NULL},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"redirlog file","",setoutput,{NULL},TELNETSRV_CMDFLAG_WEBSRVONLY,NULL},
|
||||
{"redirlog off","",setoutput,{NULL},TELNETSRV_CMDFLAG_WEBSRVONLY,NULL},
|
||||
{"param","[prio]",setparam,{wsetparam},0,NULL},
|
||||
{"history","[list,reset]",history_cmd,{NULL},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
|
||||
|
||||
@@ -127,36 +134,40 @@ void client_printf(const char *message, ...) {
|
||||
return ;
|
||||
}
|
||||
|
||||
#define NICE_MAX 19
|
||||
#define NICE_MIN -20
|
||||
|
||||
void set_sched(pthread_t tid, int pid, int priority) {
|
||||
int rt;
|
||||
struct sched_param schedp;
|
||||
int policy;
|
||||
char strpolicy[10];
|
||||
int niceval=0;
|
||||
|
||||
//sched_get_priority_max(SCHED_FIFO)
|
||||
if (priority < NICE_MIN) {
|
||||
if (priority < -100 && priority > -200) { //RR priority 1 to 99 (high) mapped to oai priority -101 to -199 (high)
|
||||
policy=SCHED_RR;
|
||||
sprintf(strpolicy,"%s","RR");
|
||||
schedp.sched_priority= -(priority + 100 );
|
||||
} else if (priority < 0 && priority > -100 ) {
|
||||
policy=SCHED_FIFO;
|
||||
sprintf(strpolicy,"%s","fifo");
|
||||
schedp.sched_priority= NICE_MIN - priority ;
|
||||
|
||||
if ( (schedp.sched_priority < sched_get_priority_min(SCHED_FIFO)) ||
|
||||
(schedp.sched_priority > sched_get_priority_max(SCHED_FIFO)) ) {
|
||||
client_printf("Error: %i invalid prio, should be %i to %i, \n",
|
||||
priority, NICE_MIN -sched_get_priority_min(SCHED_FIFO),
|
||||
NICE_MIN - sched_get_priority_max(SCHED_FIFO) );
|
||||
}
|
||||
} else if (priority > NICE_MAX) {
|
||||
schedp.sched_priority= -priority ;//fifo priority 1 to 99 (high) mapped to oai priority -1 to -99 (high)
|
||||
} else if (priority >= 0 && priority <= (NICE_MAX-NICE_MIN)) { // other (normal) nice value -20 to 19 mapped to oai priority 0 to 39
|
||||
policy=SCHED_OTHER;
|
||||
sprintf(strpolicy,"%s","other");
|
||||
schedp.sched_priority=0;
|
||||
niceval=priority+NICE_MIN;
|
||||
} else if (priority > NICE_MAX-NICE_MIN && priority <= (2*(NICE_MAX-NICE_MIN)+1) ) {// batch (normal) nice value -20 to 19 mapped to oai priority 40 to 79
|
||||
policy=SCHED_BATCH;
|
||||
sprintf(strpolicy,"%s","batch");
|
||||
niceval=priority+NICE_MIN-(NICE_MAX-NICE_MIN+1);
|
||||
schedp.sched_priority=0;
|
||||
} else if (priority > (2*(NICE_MAX-NICE_MIN)+1)){// fifo mapped to oai priority 80
|
||||
policy=SCHED_IDLE;
|
||||
sprintf(strpolicy,"%s","idle");
|
||||
schedp.sched_priority=0;
|
||||
} else {
|
||||
policy=SCHED_OTHER;
|
||||
sprintf(strpolicy,"%s","other");
|
||||
schedp.sched_priority=0;
|
||||
client_printf("Error: %i invalid priority \n",priority );
|
||||
return;
|
||||
}
|
||||
|
||||
if( tid != 0) {
|
||||
rt = pthread_setschedparam(tid, policy, &schedp);
|
||||
} else if(pid > 0) {
|
||||
@@ -172,15 +183,15 @@ void set_sched(pthread_t tid, int pid, int priority) {
|
||||
} else {
|
||||
client_printf("policy set to %s, priority %i\n",strpolicy,schedp.sched_priority);
|
||||
|
||||
if ( policy==SCHED_OTHER) {
|
||||
if ( policy==SCHED_OTHER || policy==SCHED_BATCH ) {
|
||||
rt = getpriority(PRIO_PROCESS,tid);
|
||||
|
||||
if (rt != -1) {
|
||||
rt = setpriority(PRIO_PROCESS,tid,priority);
|
||||
rt = setpriority(PRIO_PROCESS,tid,niceval);
|
||||
|
||||
if (rt < 0) {
|
||||
client_printf("Error %i: %s trying to set nice value of thread %u to %i\n",
|
||||
errno,strerror(errno),tid,priority);
|
||||
errno,strerror(errno),tid,niceval);
|
||||
}
|
||||
} else {
|
||||
client_printf("Error %i: %s trying to get nice value of thread %u \n",
|
||||
@@ -189,17 +200,17 @@ void set_sched(pthread_t tid, int pid, int priority) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( policy == SCHED_OTHER) {
|
||||
if ( policy == SCHED_OTHER || policy==SCHED_BATCH) {
|
||||
if ( tid > 0 && tid != pthread_self()) {
|
||||
client_printf("setting nice value using a thread id not implemented....\n");
|
||||
} else if (pid > 0) {
|
||||
errno=0;
|
||||
rt = setpriority(PRIO_PROCESS,pid,priority);
|
||||
rt = setpriority(PRIO_PROCESS,pid,niceval);
|
||||
|
||||
if (rt != 0) {
|
||||
client_printf("Error %i: %s calling setpriority, \n",errno,strerror(errno));
|
||||
} else {
|
||||
client_printf("nice value set to %i\n",priority);
|
||||
client_printf("nice value set to %i\n",niceval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,20 +247,29 @@ void redirstd(char *newfname,telnet_printfunc_t prnt ) {
|
||||
fd=freopen(newfname, "w", stdout);
|
||||
|
||||
if (fd == NULL) {
|
||||
prnt("ERROR: stdout redir to %s error %s",strerror(errno));
|
||||
prnt("ERROR: stdout redir to %s error %s\n",strerror(errno));
|
||||
} else {
|
||||
prnt("stdout redirected to %s\n",newfname);
|
||||
}
|
||||
|
||||
fd=freopen(newfname, "w", stderr);
|
||||
|
||||
if (fd == NULL) {
|
||||
prnt("ERROR: stderr redir to %s error %s",strerror(errno));
|
||||
prnt("ERROR: stderr redir to %s error %s\n",strerror(errno));
|
||||
} else {
|
||||
prnt("stderr redirected to %s\n",newfname);
|
||||
}
|
||||
}
|
||||
|
||||
int wsetoutput(char *buffer, int debug, telnet_printfunc_t prnt, ... ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setoutput(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
char cmds[TELNET_MAX_MSGLENGTH/TELNET_CMD_MAXSIZE][TELNET_CMD_MAXSIZE];
|
||||
char *logfname;
|
||||
char stdout_str[64];
|
||||
#define LOGFILE "logfile.log"
|
||||
|
||||
memset(cmds,0,sizeof(cmds));
|
||||
sscanf(buff,"%9s %32s %9s %9s %9s", cmds[0],cmds[1],cmds[2],cmds[3],cmds[4] );
|
||||
|
||||
@@ -265,10 +285,10 @@ int setoutput(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
|
||||
if (strncasecmp(cmds[0],"file",4) == 0) {
|
||||
if (cmds[1][0] == 0)
|
||||
logfname=LOGFILE;
|
||||
logfname=telnetparams.logfile;
|
||||
else
|
||||
logfname=cmds[1];
|
||||
|
||||
prnt("Log output redirected to (%s)\n",logfname);
|
||||
fflush(stdout);
|
||||
redirstd(logfname,prnt);
|
||||
}
|
||||
@@ -281,6 +301,10 @@ int setoutput(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
return CMDSTATUS_FOUND;
|
||||
} /* setoutput */
|
||||
|
||||
int wsetparam(char *buff, int debug, telnet_printfunc_t prnt, ...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setparam(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
char cmds[TELNET_MAX_MSGLENGTH/TELNET_CMD_MAXSIZE][TELNET_CMD_MAXSIZE];
|
||||
memset(cmds,0,sizeof(cmds));
|
||||
@@ -344,6 +368,98 @@ int history_cmd(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
/*
|
||||
generic commands available for all modules loaded by the server
|
||||
*/
|
||||
char *telnet_getvarvalue(telnetshell_vardef_t *var, int varindex) {
|
||||
char *val;
|
||||
switch(var[varindex].vartype) {
|
||||
case TELNET_VARTYPE_INT32:
|
||||
val=malloc(64);
|
||||
snprintf(val,64,"%i",*(int32_t *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT64:
|
||||
val=malloc(128);
|
||||
snprintf(val,128,"%lli",(long long)*(int64_t *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
val=malloc(16);
|
||||
snprintf(val,16,"%hi",*(short *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
val=malloc(16);
|
||||
snprintf(val,16,"%i",(int)(*(int8_t *)(var[varindex].varvalptr)));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
val=malloc(64);
|
||||
snprintf(val,64,"%u",*(unsigned int *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
val=malloc(32);
|
||||
snprintf(val,32,"%g\n",*(double *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_STRING:
|
||||
val = strdup(*(char **)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
val=malloc(64);
|
||||
snprintf(val,64,"ERR:var %i unknown type",varindex);
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
int telnet_setvarvalue(telnetshell_vardef_t *var,char *strval, telnet_printfunc_t prnt ) {
|
||||
int st=0;
|
||||
switch(var->vartype) {
|
||||
case TELNET_VARTYPE_INT32:
|
||||
*(int *)(var->varvalptr) = (int)strtol(strval,NULL,0);
|
||||
if (prnt != NULL)
|
||||
prnt("%i\n",*(int *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
*(short *)(var->varvalptr) = (short)strtol(strval,NULL,0);
|
||||
if (prnt != NULL)
|
||||
prnt("%hi\n",*(short *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
*(char *)(var->varvalptr) = (char)strtol(strval,NULL,0);
|
||||
if (prnt != NULL)
|
||||
prnt("%i\n",*(int *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
*(unsigned int *)(var->varvalptr) = (unsigned int)strtol(strval,NULL,0);
|
||||
if (prnt != NULL)
|
||||
prnt("%u\n",*(unsigned int *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
*(double *)(var->varvalptr) = strtod(strval,NULL);
|
||||
if (prnt != NULL)
|
||||
prnt("%g\n",*(double *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_STRING:
|
||||
sprintf(*(char **)(var->varvalptr),"%s", strval);
|
||||
if (prnt != NULL)
|
||||
prnt("\"%s\"\n",*(char **)(var->varvalptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (prnt != NULL)
|
||||
prnt("unknown type\n");
|
||||
st=-1;
|
||||
break;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
int setgetvar(int moduleindex,char getorset,char *params) {
|
||||
int n,i;
|
||||
@@ -357,81 +473,15 @@ int setgetvar(int moduleindex,char getorset,char *params) {
|
||||
if (n > 0 && (getorset == 'g' || getorset == 'G')) {
|
||||
client_printf("%s, %s = ", telnetparams.CmdParsers[moduleindex].module,
|
||||
telnetparams.CmdParsers[moduleindex].var[i].varname );
|
||||
|
||||
switch(telnetparams.CmdParsers[moduleindex].var[i].vartype) {
|
||||
case TELNET_VARTYPE_INT32:
|
||||
client_printf("%i\n",*(int32_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT64:
|
||||
client_printf("%lli\n",*(int64_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
client_printf("%i\n",(int)(*(int8_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_STRING:
|
||||
client_printf("\"%s\"\n",*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
client_printf("unknown type\n");
|
||||
break;
|
||||
}
|
||||
char *strval=telnet_getvarvalue(telnetparams.CmdParsers[moduleindex].var, i);
|
||||
client_printf("%s\n",strval);
|
||||
free(strval);
|
||||
}
|
||||
|
||||
if (n > 1 && (getorset == 's' || getorset == 'S')) {
|
||||
client_printf("%s, %s set to \n", telnetparams.CmdParsers[moduleindex].module,
|
||||
telnetparams.CmdParsers[moduleindex].var[i].varname);
|
||||
telnet_setvarvalue(&(telnetparams.CmdParsers[moduleindex].var[i]),varval, client_printf);
|
||||
|
||||
switch(telnetparams.CmdParsers[moduleindex].var[i].vartype) {
|
||||
case TELNET_VARTYPE_INT32:
|
||||
*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (int)strtol(varval,NULL,0);
|
||||
client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (short)strtol(varval,NULL,0);
|
||||
client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
*(char *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (char)strtol(varval,NULL,0);
|
||||
client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (unsigned int)strtol(varval,NULL,0);
|
||||
client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = strtod(varval,NULL);
|
||||
client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_STRING:
|
||||
sprintf(*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr),"%s", varval);
|
||||
client_printf("\"%s\"\n",*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
client_printf("unknown type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,6 +492,13 @@ int setgetvar(int moduleindex,char getorset,char *params) {
|
||||
|
||||
return CMDSTATUS_VARNOTFOUND;
|
||||
}
|
||||
|
||||
void telnetsrv_freetbldata(webdatadef_t *wdata) {
|
||||
for(int i=0;i< wdata->numlines; i++)
|
||||
for(int j=0;j< wdata->numcols ; j++)
|
||||
if ( wdata->columns[j].coltype & TELNET_VAR_NEEDFREE )
|
||||
free(wdata->lines[i].val[j]);
|
||||
}
|
||||
/*----------------------------------------------------------------------------------------------------*/
|
||||
char *get_time(char *buff,int bufflen) {
|
||||
struct tm tmstruct;
|
||||
@@ -449,6 +506,16 @@ char *get_time(char *buff,int bufflen) {
|
||||
strftime (buff, bufflen, "%Y-%m-%d %H:%M:%S.000", localtime_r(&now,&tmstruct));
|
||||
return buff;
|
||||
}
|
||||
void telnet_pushcmd(telnetshell_cmddef_t *cmd, char *cmdbuff, telnet_printfunc_t prnt) {
|
||||
notifiedFIFO_elt_t *msg =newNotifiedFIFO_elt(sizeof(telnetsrv_qmsg_t),0,NULL,NULL);
|
||||
telnetsrv_qmsg_t *cmddata=NotifiedFifoData(msg);
|
||||
cmddata->cmdfunc=(qcmdfunc_t)cmd->cmdfunc;
|
||||
cmddata->prnt=prnt;
|
||||
cmddata->debug=telnetparams.telnetdbg;
|
||||
if (cmdbuff != NULL)
|
||||
cmddata->cmdbuff=strdup(cmdbuff);
|
||||
pushNotifiedFIFO(cmd->qptr, msg);
|
||||
}
|
||||
|
||||
int process_command(char *buf) {
|
||||
int i,j,k;
|
||||
@@ -459,7 +526,7 @@ int process_command(char *buf) {
|
||||
int rt;
|
||||
memset(modulename,0,sizeof(modulename));
|
||||
memset(cmd,0,sizeof(cmd));
|
||||
|
||||
extern char **environ;
|
||||
|
||||
if (strncasecmp(buf,"ex",2) == 0)
|
||||
return CMDSTATUS_EXIT;
|
||||
@@ -474,6 +541,8 @@ int process_command(char *buf) {
|
||||
}
|
||||
|
||||
for(j=0; telnetparams.CmdParsers[i].cmd[j].cmdfunc != NULL ; j++) {
|
||||
if ( telnetparams.CmdParsers[i].cmd[j].cmdflags & TELNETSRV_CMDFLAG_WEBSRVONLY )
|
||||
continue;
|
||||
client_printf(" %s %s %s\n",
|
||||
telnetparams.CmdParsers[i].module,telnetparams.CmdParsers[i].cmd[j].cmdname,
|
||||
telnetparams.CmdParsers[i].cmd[j].helpstr);
|
||||
@@ -489,7 +558,7 @@ int process_command(char *buf) {
|
||||
j = sscanf(buf,"%19s %19s %m[^\t\n]",modulename,cmd,&cmdb);
|
||||
|
||||
if (telnetparams.telnetdbg > 0)
|
||||
printf("process_command: %i words, module=%s cmd=%s, parameters= %s\n",j,modulename,cmd,cmdb);
|
||||
printf("process_command: %i words, module=%s cmd=%s, parameters= %s\n",j,modulename,cmd,(cmdb==NULL)?"":cmdb);
|
||||
|
||||
for (i=0; j>=2 && telnetparams.CmdParsers[i].var != NULL && telnetparams.CmdParsers[i].cmd != NULL; i++) {
|
||||
if ( (strncasecmp(telnetparams.CmdParsers[i].module,modulename,strlen(telnetparams.CmdParsers[i].module)) == 0)) {
|
||||
@@ -504,14 +573,10 @@ int process_command(char *buf) {
|
||||
} else {
|
||||
for (k=0 ; telnetparams.CmdParsers[i].cmd[k].cmdfunc != NULL ; k++) {
|
||||
if (strncasecmp(cmd, telnetparams.CmdParsers[i].cmd[k].cmdname,sizeof(telnetparams.CmdParsers[i].cmd[k].cmdname)) == 0) {
|
||||
if (telnetparams.CmdParsers[i].cmd[k].cmdflags & TELNETSRV_CMDFLAG_WEBSRVONLY)
|
||||
continue;
|
||||
if (telnetparams.CmdParsers[i].cmd[k].qptr != NULL) {
|
||||
notifiedFIFO_elt_t *msg =newNotifiedFIFO_elt(sizeof(telnetsrv_qmsg_t),0,NULL,NULL);
|
||||
telnetsrv_qmsg_t *cmddata=NotifiedFifoData(msg);
|
||||
cmddata->cmdfunc=(qcmdfunc_t)telnetparams.CmdParsers[i].cmd[k].cmdfunc;
|
||||
cmddata->prnt=client_printf;
|
||||
cmddata->debug=telnetparams.telnetdbg;
|
||||
cmddata->cmdbuff=strdup(cmdb);
|
||||
pushNotifiedFIFO(telnetparams.CmdParsers[i].cmd[k].qptr, msg);
|
||||
telnet_pushcmd(&(telnetparams.CmdParsers[i].cmd[k]), cmdb,client_printf );
|
||||
} else {
|
||||
telnetparams.CmdParsers[i].cmd[k].cmdfunc(cmdb, telnetparams.telnetdbg, client_printf);
|
||||
}
|
||||
@@ -859,12 +924,14 @@ int add_telnetcmd(char *modulename, telnetshell_vardef_t *var, telnetshell_cmdde
|
||||
strncpy(telnetparams.CmdParsers[i].module,modulename,sizeof(telnetparams.CmdParsers[i].module)-1);
|
||||
telnetparams.CmdParsers[i].cmd = cmd;
|
||||
telnetparams.CmdParsers[i].var = var;
|
||||
if (cmd->cmdflags & TELNETSRV_CMDFLAG_PUSHINTPOOLQ) {
|
||||
for (int j=0; cmd[j].cmdfunc != NULL ;j++) {
|
||||
if (cmd[j].cmdflags & TELNETSRV_CMDFLAG_PUSHINTPOOLQ) {
|
||||
if (afifo == NULL) {
|
||||
afifo = malloc(sizeof(notifiedFIFO_t));
|
||||
initNotifiedFIFO(afifo);
|
||||
}
|
||||
cmd->qptr = afifo;
|
||||
cmd[j].qptr = afifo;
|
||||
}
|
||||
}
|
||||
printf("[TELNETSRV] Telnet server: module %i = %s added to shell\n",
|
||||
i,telnetparams.CmdParsers[i].module);
|
||||
@@ -894,10 +961,16 @@ int telnetsrv_checkbuildver(char *mainexec_buildversion, char **shlib_buildvers
|
||||
}
|
||||
|
||||
int telnetsrv_getfarray(loader_shlibfunc_t **farray) {
|
||||
*farray=malloc(sizeof(loader_shlibfunc_t)*2);
|
||||
*farray=malloc(sizeof(loader_shlibfunc_t)*3);
|
||||
(*farray)[0].fname=TELNET_ADDCMD_FNAME;
|
||||
(*farray)[0].fptr=(int (*)(void) )add_telnetcmd;
|
||||
(*farray)[1].fname=TELNET_POLLCMDQ_FNAME;
|
||||
(*farray)[1].fptr=(int (*)(void) )poll_telnetcmdq;
|
||||
return ( 2);
|
||||
(*farray)[2].fname=TELNET_PUSHCMD_FNAME;
|
||||
(*farray)[2].fptr=(int (*)(void) )telnet_pushcmd;
|
||||
return ( 3);
|
||||
}
|
||||
/* for webserver interface, needs access to some telnet server paramaters */
|
||||
telnetsrv_params_t *get_telnetsrv_params(void) {
|
||||
return &telnetparams;
|
||||
}
|
||||
|
||||
@@ -48,19 +48,55 @@
|
||||
#define CMDSTATUS_VARNOTFOUND 3
|
||||
#define CMDSTATUS_NOTFOUND 4
|
||||
|
||||
/* definitions to store 2 dim table, used to store command results before */
|
||||
/* displaying them either on console or web page */
|
||||
#define TELNET_MAXLINE_NUM 100
|
||||
#define TELNET_MAXCOL_NUM 10
|
||||
|
||||
typedef struct col {
|
||||
char coltitle[TELNET_CMD_MAXSIZE];
|
||||
unsigned int coltype;
|
||||
} acol_t;
|
||||
|
||||
typedef struct line {
|
||||
char *val[TELNET_MAXCOL_NUM];
|
||||
} aline_t;
|
||||
|
||||
typedef struct webdatadef {
|
||||
char tblname[TELNET_HELPSTR_SIZE];
|
||||
int numlines;
|
||||
int numcols;
|
||||
acol_t columns[TELNET_MAXCOL_NUM];
|
||||
aline_t lines[TELNET_MAXLINE_NUM];
|
||||
} webdatadef_t;
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* structure to be used when adding a module to the telnet server */
|
||||
/* This is the second parameter of the add_telnetcmd function, which can be used */
|
||||
/* to add a set of new command to the telnet server shell */
|
||||
typedef void(*telnet_printfunc_t)(const char* format, ...);
|
||||
typedef int(*cmdfunc_t)(char*, int, telnet_printfunc_t prnt);
|
||||
typedef int(*webfunc_t)(char *cmdbuff, int debug, telnet_printfunc_t prnt, ... );
|
||||
typedef int(*webfunc_getdata_t)(char *cmdbuff, int debug, void *data,telnet_printfunc_t prnt);
|
||||
typedef int(*qcmdfunc_t)(char*, int, telnet_printfunc_t prnt,void *arg);
|
||||
|
||||
#define TELNETSRV_CMDFLAG_PUSHINTPOOLQ (1<<0) // ask the telnet server to push the command in a thread pool queue
|
||||
#define TELNETSRV_CMDFLAG_PUSHINTPOOLQ (1<<0) // ask the telnet server to push the command in a thread pool queue
|
||||
#define TELNETSRV_CMDFLAG_GETWEBDATA (1<<1) // When called from web server, use the getdata variant of the function
|
||||
#define TELNETSRV_CMDFLAG_TELNETONLY (1<<2) // Command only for telnet client connections
|
||||
#define TELNETSRV_CMDFLAG_WEBSRVONLY (1<<3) // Command only for web server connections
|
||||
#define TELNETSRV_CMDFLAG_CONFEXEC (1<<4) // Ask for confirm before exec
|
||||
#define TELNETSRV_CMDFLAG_GETWEBTBLDATA (1<<8) // When called from web server, use the get table data variant of the function
|
||||
#define TELNETSRV_CMDFLAG_PRINTWEBTBLDATA (1<<9) // websrv Print as a single column table
|
||||
#define TELNETSRV_CMDFLAG_NEEDPARAM (1<<10) // websrv: The command needs a parameter
|
||||
#define TELNETSRV_CMDFLAG_WEBSRV_SETRETURNTBL (1<<11) // websrv: set callback returns a new table
|
||||
#define TELNETSRV_CMDFLAG_AUTOUPDATE (1<<12) // command can be re-submitted automatically for result update
|
||||
typedef struct cmddef {
|
||||
char cmdname[TELNET_CMD_MAXSIZE];
|
||||
char helpstr[TELNET_HELPSTR_SIZE];
|
||||
cmdfunc_t cmdfunc;
|
||||
cmdfunc_t cmdfunc;
|
||||
union {
|
||||
webfunc_t webfunc;
|
||||
webfunc_getdata_t webfunc_getdata;
|
||||
};
|
||||
unsigned int cmdflags;
|
||||
void *qptr;
|
||||
} telnetshell_cmddef_t;
|
||||
@@ -78,6 +114,8 @@ typedef struct telnetsrv_qmsg {
|
||||
/*structure to be used when adding a module to the telnet server */
|
||||
/* This is the first parameter of the add_telnetcmd function, which can be used */
|
||||
/* to add a set of new variables which can be got/set from the telnet server shell */
|
||||
/* var type: bits 0-3, type value (1 to 15)
|
||||
* type modifier, bits 4-31 */
|
||||
#define TELNET_VARTYPE_INT32 1
|
||||
#define TELNET_VARTYPE_INT16 2
|
||||
#define TELNET_VARTYPE_INT64 3
|
||||
@@ -85,10 +123,18 @@ typedef struct telnetsrv_qmsg {
|
||||
#define TELNET_VARTYPE_DOUBLE 5
|
||||
#define TELNET_VARTYPE_INT8 6
|
||||
#define TELNET_VARTYPE_UINT 7
|
||||
|
||||
#define TELNET_CHECKVAL_RDONLY 16
|
||||
#define TELNET_CHECKVAL_BOOL 32
|
||||
#define TELNET_VAR_NEEDFREE 64
|
||||
#define TELNET_CHECKVAL_LOGLVL 128
|
||||
#define TELNET_CHECKVAL_SIMALGO 256
|
||||
typedef struct variabledef {
|
||||
char varname[TELNET_CMD_MAXSIZE];
|
||||
char vartype;
|
||||
char checkval;
|
||||
void *varvalptr;
|
||||
|
||||
} telnetshell_vardef_t;
|
||||
|
||||
|
||||
@@ -113,6 +159,7 @@ typedef struct {
|
||||
int priority; // server running priority
|
||||
char *histfile; // command history
|
||||
int histsize; // command history length
|
||||
char *logfile; // filename to use when redirecting output to file
|
||||
int new_socket; // socket of the client connection
|
||||
int logfilefd; // file id of the log file when log output is redirected to a file
|
||||
int saved_stdout; // file id of the previous stdout, used to be able to restore original stdout
|
||||
@@ -145,14 +192,25 @@ VT escape sequence definition, for smarter display....
|
||||
#define STDFMT "\x1b[0m"
|
||||
|
||||
/*---------------------------------------------------------------------------------------------*/
|
||||
#define TELNET_ADDCMD_FNAME "add_telnetcmd"
|
||||
#define NICE_MAX 19
|
||||
#define NICE_MIN -20
|
||||
#define TELNET_ADDCMD_FNAME "add_telnetcmd"
|
||||
#define TELNET_POLLCMDQ_FNAME "poll_telnetcmdq"
|
||||
#define TELNET_PUSHCMD_FNAME "telnet_pushcmd"
|
||||
typedef int(*add_telnetcmd_func_t)(char *, telnetshell_vardef_t *, telnetshell_cmddef_t *);
|
||||
typedef void(*poll_telnetcmdq_func_t)(void *qid,void *arg);
|
||||
typedef void(*push_telnetcmd_func_t)(telnetshell_cmddef_t *cmd, char *cmdbuff, telnet_printfunc_t prnt);
|
||||
#ifdef TELNETSERVERCODE
|
||||
int add_telnetcmd(char *modulename, telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd);
|
||||
void set_sched(pthread_t tid, int pid,int priority);
|
||||
void set_affinity(pthread_t tid, int pid, int coreid);
|
||||
extern int get_phybsize(void);
|
||||
#endif
|
||||
#ifdef WEBSERVERCODE
|
||||
extern void telnet_pushcmd(telnetshell_cmddef_t *cmd, char *cmdbuff, telnet_printfunc_t prnt);
|
||||
extern telnetsrv_params_t *get_telnetsrv_params(void);
|
||||
extern char *telnet_getvarvalue(telnetshell_vardef_t *var, int varindex);
|
||||
extern int telnet_setvarvalue(telnetshell_vardef_t *var,char *strval, telnet_printfunc_t prnt ) ;
|
||||
extern void telnetsrv_freetbldata(webdatadef_t *wdata);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -30,6 +30,6 @@ endforeach()
|
||||
|
||||
install(TARGETS telnetsrv DESTINATION bin)
|
||||
|
||||
if (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build")
|
||||
install(TARGETS telnetsrv DESTINATION ${OPENAIR_BUILD_DIR}/ran_build/build)
|
||||
endif (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build")
|
||||
if (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
|
||||
install(TARGETS telnetsrv DESTINATION ${OPENAIR_CMAKE}/ran_build/build)
|
||||
endif (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
|
||||
|
||||
@@ -110,9 +110,8 @@ int dump_phyvars(char *buf, int debug, telnet_printfunc_t prnt) {
|
||||
|
||||
|
||||
telnetshell_cmddef_t phy_cmdarray[] = {
|
||||
{"disp","[phycnt,uedump,uestat UE<x>]", dump_phyvars},
|
||||
|
||||
{"","",NULL},
|
||||
{"disp","[phycnt,uedump,uestat UE<x>]", dump_phyvars,{NULL},0,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -42,24 +42,29 @@
|
||||
|
||||
int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
telnetshell_cmddef_t loader_cmdarray[] = {
|
||||
{"show","[params,modules]",loader_show_cmd},
|
||||
{"","",NULL},
|
||||
{"show","[params,modules]",loader_show_cmd,{(webfunc_t)loader_show_cmd},0,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (buff == NULL) {
|
||||
prnt("ERROR wrong loader SHOW command...\n");
|
||||
return 0;
|
||||
}
|
||||
if (debug > 0)
|
||||
prnt( "loader_show_cmd received %s\n",buff);
|
||||
|
||||
|
||||
if (strcasestr(buff,"params") != NULL) {
|
||||
prnt( "loader parameters:\n");
|
||||
prnt( " Main executable build version: \"%s\"\n", loader_data.mainexec_buildversion);
|
||||
prnt( " Default shared lib path: \"%s\"\n", loader_data.shlibpath);
|
||||
prnt( " Max number of shared lib : %i\n", loader_data.maxshlibs);
|
||||
}
|
||||
else if (strcasestr(buff,"modules") != NULL) {
|
||||
else if (strcasestr(buff,"modules") != NULL || buff[0]==0 || strcasestr(buff,"show") != NULL) {
|
||||
prnt( "%i shared lib have been dynamicaly loaded by the oai loader\n", loader_data.numshlibs);
|
||||
for (int i=0 ; i<loader_data.numshlibs ; i++) {
|
||||
prnt( " Module %i: %s\n", i,loader_data.shlibs[i].name);
|
||||
|
||||
@@ -39,11 +39,11 @@
|
||||
|
||||
|
||||
telnetshell_vardef_t loader_globalvardef[] = {
|
||||
{"mainversion",TELNET_VARTYPE_STRING,&(loader_data.mainexec_buildversion)},
|
||||
{"defpath",TELNET_VARTYPE_STRING,&(loader_data.shlibpath)},
|
||||
{"maxshlibs",TELNET_VARTYPE_INT32,&(loader_data.maxshlibs)},
|
||||
{"numshlibs",TELNET_VARTYPE_INT32,&(loader_data.numshlibs)},
|
||||
{"",0,NULL}
|
||||
{"mainversion",TELNET_VARTYPE_STRING,TELNET_CHECKVAL_RDONLY, &(loader_data.mainexec_buildversion)},
|
||||
{"defpath",TELNET_VARTYPE_STRING,TELNET_CHECKVAL_RDONLY,&(loader_data.shlibpath)},
|
||||
{"maxshlibs",TELNET_VARTYPE_INT32,TELNET_CHECKVAL_RDONLY,&(loader_data.maxshlibs)},
|
||||
{"numshlibs",TELNET_VARTYPE_INT32,TELNET_CHECKVAL_RDONLY,&(loader_data.numshlibs)},
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
telnetshell_vardef_t *loader_modulesvardef;
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ telnetshell_cmddef_t measur_cmdarray[] = {
|
||||
};
|
||||
|
||||
telnetshell_vardef_t measur_vardef[] = {
|
||||
{"",0,NULL}
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
/* function to be implemented in any telnetsrv_xxx_measurements.c sources
|
||||
to allow common measurment code to access measurments data */
|
||||
|
||||
@@ -53,7 +53,7 @@ telnetshell_vardef_t phy_vardef[] = {
|
||||
//{"txshift",TELNET_VARTYPE_INT32,NULL},
|
||||
//{"rachemin",TELNET_VARTYPE_INT32,NULL},
|
||||
//{"rachdmax",TELNET_VARTYPE_INT32,NULL},
|
||||
{"",0,NULL}
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
@@ -57,89 +57,121 @@
|
||||
#include "openair1/PHY/phy_extern.h"
|
||||
#include "telnetsrv_proccmd.h"
|
||||
|
||||
void decode_procstat(char *record, int debug, telnet_printfunc_t prnt)
|
||||
void decode_procstat(char *record, int debug, telnet_printfunc_t prnt,webdatadef_t *tdata)
|
||||
{
|
||||
char prntline[160];
|
||||
char *procfile_fiels;
|
||||
char *procfile_fields;
|
||||
char *strtokptr;
|
||||
char *lptr;
|
||||
int fieldcnt;
|
||||
char toksep[2];
|
||||
|
||||
fieldcnt=0;
|
||||
procfile_fiels =strtok_r(record," ",&strtokptr);
|
||||
procfile_fields =strtok_r(record," ",&strtokptr);
|
||||
lptr= prntline;
|
||||
/*http://man7.org/linux/man-pages/man5/proc.5.html gives the structure of the stat file */
|
||||
|
||||
while( procfile_fiels != NULL && fieldcnt < 42) {
|
||||
int priority=0;
|
||||
int nice=0;
|
||||
while( procfile_fields != NULL && fieldcnt < 42) {
|
||||
long int policy;
|
||||
if (strlen(procfile_fiels) == 0)
|
||||
if (strlen(procfile_fields) == 0)
|
||||
continue;
|
||||
fieldcnt++;
|
||||
sprintf(toksep," ");
|
||||
switch(fieldcnt) {
|
||||
case 1: /* id */
|
||||
lptr+=sprintf(lptr,"%9.9s ",procfile_fiels);
|
||||
sprintf(toksep,")");
|
||||
if (tdata != NULL) {
|
||||
tdata->lines[tdata->numlines].val[0]=strdup(procfile_fields);
|
||||
}
|
||||
lptr+=sprintf(lptr,"%9.9s ",procfile_fields);
|
||||
sprintf(toksep,")");
|
||||
break;
|
||||
case 2: /* name */
|
||||
lptr+=sprintf(lptr,"%20.20s ",procfile_fiels+1);
|
||||
if (tdata != NULL) {
|
||||
tdata->lines[tdata->numlines].val[1]=strdup(procfile_fields);
|
||||
}
|
||||
lptr+=sprintf(lptr,"%20.20s ",procfile_fields+1);
|
||||
break;
|
||||
case 3: //thread state
|
||||
lptr+=sprintf(lptr," %c ",procfile_fiels[0]);
|
||||
lptr+=sprintf(lptr," %c ",procfile_fields[0]);
|
||||
break;
|
||||
case 14: //time in user mode
|
||||
case 15: //time in kernel mode
|
||||
lptr+=sprintf(lptr,"%9.9s ",procfile_fiels);
|
||||
lptr+=sprintf(lptr,"%9.9s ",procfile_fields);
|
||||
break;
|
||||
case 18: //priority
|
||||
case 19: //nice
|
||||
lptr+=sprintf(lptr,"%3.3s ",procfile_fiels);
|
||||
case 18: //priority column index 2 in tdata, -2 to -100 (1, min to 99, highest prio)
|
||||
priority=strtol(procfile_fields,NULL,0);
|
||||
case 19: //nice column index 3 in tdata 0 to 39 (-20, highest prio, to 19)
|
||||
if (tdata != NULL) {
|
||||
tdata->lines[tdata->numlines].val[fieldcnt-16]=strdup(procfile_fields);
|
||||
}
|
||||
lptr+=sprintf(lptr,"%3.3s ",procfile_fields);
|
||||
nice=strtol(procfile_fields,NULL,0);
|
||||
break;
|
||||
case 23: //vsize
|
||||
lptr+=sprintf(lptr,"%9.9s ",procfile_fiels);
|
||||
lptr+=sprintf(lptr,"%9.9s ",procfile_fields);
|
||||
break;
|
||||
case 39: //processor
|
||||
lptr+=sprintf(lptr," %2.2s ",procfile_fiels);
|
||||
case 39: //processor
|
||||
if (tdata != NULL) {
|
||||
tdata->lines[tdata->numlines].val[4]=strdup(procfile_fields);
|
||||
}
|
||||
lptr+=sprintf(lptr," %2.2s ",procfile_fields);
|
||||
break;
|
||||
case 41: //policy
|
||||
lptr+=sprintf(lptr,"%3.3s ",procfile_fiels);
|
||||
policy=strtol(procfile_fiels,NULL,0);
|
||||
lptr+=sprintf(lptr,"%3.3s ",procfile_fields);
|
||||
policy=strtol(procfile_fields,NULL,0);
|
||||
char strschedp[64];
|
||||
switch(policy) {
|
||||
case SCHED_FIFO:
|
||||
lptr+=sprintf(lptr,"%s ","rt: fifo");
|
||||
snprintf(strschedp,sizeof(strschedp),"%s ","rt:fifo");
|
||||
priority= priority+1; //in /proc file system priority 1 to 99 mapped to -2 to -100
|
||||
break;
|
||||
case SCHED_OTHER:
|
||||
lptr+=sprintf(lptr,"%s ","other");
|
||||
snprintf(strschedp,sizeof(strschedp),"%s ","other");
|
||||
priority=nice-NICE_MIN; // linux nice is -20 to 19
|
||||
break;
|
||||
case SCHED_IDLE:
|
||||
lptr+=sprintf(lptr,"%s ","idle");
|
||||
snprintf(strschedp,sizeof(strschedp),"%s ","idle");
|
||||
priority=2*(NICE_MAX-NICE_MIN+1);
|
||||
break;
|
||||
case SCHED_BATCH:
|
||||
lptr+=sprintf(lptr,"%s ","batch");
|
||||
snprintf(strschedp,sizeof(strschedp),"%s ","batch");
|
||||
priority=(NICE_MAX-NICE_MIN+1)+nice-NICE_MIN;
|
||||
break;
|
||||
case SCHED_RR:
|
||||
lptr+=sprintf(lptr,"%s ","rt: rr");
|
||||
snprintf(strschedp,sizeof(strschedp),"%s ","rt:rr");
|
||||
priority= priority-99 ;
|
||||
break;
|
||||
#ifdef SCHED_DEADLINE
|
||||
case SCHED_DEADLINE:
|
||||
lptr+=sprintf(lptr,"%s ","rt: deadline");
|
||||
snprintf(strschedp,sizeof(strschedp),"%s ","rt:deadline");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
lptr+=sprintf(lptr,"%s ","????");
|
||||
snprintf(strschedp,sizeof(strschedp),"%s ","????");
|
||||
break;
|
||||
}
|
||||
lptr+=sprintf(lptr,"%s ",strschedp);
|
||||
if (tdata != NULL) {
|
||||
tdata->lines[tdata->numlines].val[5]=strdup(strschedp);
|
||||
tdata->lines[tdata->numlines].val[6]=malloc(10);
|
||||
snprintf(tdata->lines[tdata->numlines].val[6],9,"%i",priority);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}/* switch on fieldcnr */
|
||||
procfile_fiels =strtok_r(NULL,toksep,&strtokptr);
|
||||
procfile_fields =strtok_r(NULL,toksep,&strtokptr);
|
||||
} /* while on proc_fields != NULL */
|
||||
prnt("%s\n",prntline);
|
||||
if (tdata != NULL) {
|
||||
tdata->numlines++;
|
||||
}
|
||||
} /*decode_procstat */
|
||||
|
||||
void read_statfile(char *fname,int debug, telnet_printfunc_t prnt)
|
||||
|
||||
|
||||
void read_statfile(char *fname,int debug, telnet_printfunc_t prnt, webdatadef_t *tdata)
|
||||
{
|
||||
FILE *procfile;
|
||||
char arecord[1024];
|
||||
@@ -157,21 +189,55 @@ char arecord[1024];
|
||||
return;
|
||||
}
|
||||
fclose(procfile);
|
||||
decode_procstat(arecord, debug, prnt);
|
||||
decode_procstat(arecord, debug, prnt,tdata);
|
||||
}
|
||||
|
||||
void print_threads(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
int nullprnt(char *fmt,...) {
|
||||
return 0;
|
||||
}
|
||||
void proccmd_get_threaddata(char *buf, int debug, telnet_printfunc_t fprnt,webdatadef_t *tdata)
|
||||
{
|
||||
char aname[256];
|
||||
|
||||
DIR *proc_dir;
|
||||
struct dirent *entry;
|
||||
telnet_printfunc_t prnt = (fprnt != NULL)?fprnt:(telnet_printfunc_t)nullprnt;
|
||||
if (tdata != NULL) {
|
||||
tdata->numcols=7;
|
||||
snprintf(tdata->columns[0].coltitle,sizeof(tdata->columns[0].coltitle),"thread id");
|
||||
tdata->columns[0].coltype=TELNET_VARTYPE_STRING|TELNET_CHECKVAL_RDONLY|TELNET_VAR_NEEDFREE;
|
||||
snprintf(tdata->columns[1].coltitle,sizeof(tdata->columns[1].coltitle),"thread name");
|
||||
tdata->columns[1].coltype=TELNET_VARTYPE_STRING|TELNET_CHECKVAL_RDONLY|TELNET_VAR_NEEDFREE;
|
||||
snprintf(tdata->columns[2].coltitle,sizeof(tdata->columns[2].coltitle),"priority");
|
||||
tdata->columns[2].coltype=TELNET_VARTYPE_STRING|TELNET_CHECKVAL_RDONLY|TELNET_VAR_NEEDFREE;
|
||||
snprintf(tdata->columns[3].coltitle,sizeof(tdata->columns[3].coltitle),"nice");
|
||||
tdata->columns[3].coltype=TELNET_VARTYPE_STRING|TELNET_CHECKVAL_RDONLY|TELNET_VAR_NEEDFREE;
|
||||
snprintf(tdata->columns[4].coltitle,sizeof(tdata->columns[4].coltitle),"core");
|
||||
tdata->columns[4].coltype=TELNET_VARTYPE_STRING|TELNET_VAR_NEEDFREE;
|
||||
snprintf(tdata->columns[5].coltitle,sizeof(tdata->columns[5].coltitle),"sched policy");
|
||||
tdata->columns[5].coltype=TELNET_VARTYPE_STRING|TELNET_CHECKVAL_RDONLY|TELNET_VAR_NEEDFREE;
|
||||
snprintf(tdata->columns[5].coltitle,sizeof(tdata->columns[5].coltitle),"sched policy");
|
||||
tdata->columns[6].coltype=TELNET_VARTYPE_STRING|TELNET_VAR_NEEDFREE;
|
||||
snprintf(tdata->columns[6].coltitle,sizeof(tdata->columns[6].coltitle),"oai priority");
|
||||
tdata->numlines=0;
|
||||
}
|
||||
|
||||
unsigned int eax=11,ebx=0,ecx=1,edx=0;
|
||||
|
||||
asm volatile("cpuid"
|
||||
: "=a" (eax),
|
||||
"=b" (ebx),
|
||||
"=c" (ecx),
|
||||
"=d" (edx)
|
||||
: "0" (eax), "2" (ecx)
|
||||
: );
|
||||
|
||||
prnt("System has %d cores %d threads %d Actual threads",eax,ebx,edx);
|
||||
|
||||
|
||||
|
||||
prnt(" id name state USRmod KRNmod prio nice vsize proc pol \n\n");
|
||||
prnt("\n id name state USRmod KRNmod prio nice vsize proc pol \n\n");
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/stat", getpid());
|
||||
read_statfile(aname,debug,prnt);
|
||||
read_statfile(aname,debug,prnt,NULL);
|
||||
prnt("\n");
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/task", getpid());
|
||||
proc_dir = opendir(aname);
|
||||
@@ -181,20 +247,150 @@ struct dirent *entry;
|
||||
return;
|
||||
}
|
||||
|
||||
while ((entry = readdir(proc_dir)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
continue;
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/task/%.*s/stat", getpid(),(int)(sizeof(aname)-24),entry->d_name);
|
||||
read_statfile(aname,debug,prnt);
|
||||
} /* while entry != NULL */
|
||||
while ((entry = readdir(proc_dir)) != NULL){
|
||||
if(entry->d_name[0] != '.') {
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/task/%.*s/stat", getpid(),(int)(sizeof(aname)-24),entry->d_name);
|
||||
read_statfile(aname,debug,prnt,tdata);
|
||||
}
|
||||
} /* while entry != NULL */
|
||||
closedir(proc_dir);
|
||||
} /* print_threads */
|
||||
void print_threads(char *buf, int debug, telnet_printfunc_t prnt) {
|
||||
proccmd_get_threaddata(buf,debug,prnt,NULL);
|
||||
}
|
||||
|
||||
int proccmd_websrv_getdata(char *cmdbuff, int debug, void *data, telnet_printfunc_t prnt) {
|
||||
webdatadef_t *logsdata = ( webdatadef_t *) data;
|
||||
if (strncmp(cmdbuff,"set",3) == 0) {
|
||||
telnet_printfunc_t printfunc = (prnt != NULL)?prnt:( telnet_printfunc_t)printf;
|
||||
if (strcasestr(cmdbuff,"loglvl") != NULL) {
|
||||
int level=map_str_to_int(log_level_names,logsdata->lines[0].val[1]);
|
||||
int enabled=(strcmp(logsdata->lines[0].val[2],"true")==0)?1:0;
|
||||
int loginfile=(strcmp(logsdata->lines[0].val[3],"true")==0)?1:0;
|
||||
set_log(logsdata->numlines, level);
|
||||
if (enabled==0)
|
||||
set_log(logsdata->numlines, OAILOG_DISABLE);
|
||||
if ( loginfile == 1 ) {
|
||||
set_component_filelog(logsdata->numlines);
|
||||
} else {
|
||||
close_component_filelog(logsdata->numlines);
|
||||
}
|
||||
printfunc("%s log level %s is %s, output to %s\n",logsdata->lines[0].val[0],
|
||||
logsdata->lines[0].val[1], enabled?"enabled":"disabled",loginfile?g_log->log_component[logsdata->numlines].filelog_name :"stdout");
|
||||
}
|
||||
if (strcasestr(cmdbuff,"logopt") != NULL) {
|
||||
int optbit=map_str_to_int(log_options,logsdata->lines[0].val[0]);
|
||||
if (optbit < 0) {
|
||||
printfunc("option %s unknown\n",logsdata->lines[0].val[0]);
|
||||
} else {
|
||||
if(strcmp(logsdata->lines[0].val[1],"true")==0) {
|
||||
SET_LOG_OPTION(optbit);
|
||||
} else {
|
||||
CLEAR_LOG_OPTION(optbit);
|
||||
}
|
||||
printfunc("%s log option %s\n",logsdata->lines[0].val[0],(strcmp(logsdata->lines[0].val[1],"true")==0)?"enabled":"disabled");
|
||||
}
|
||||
}
|
||||
if (strcasestr(cmdbuff,"dbgopt") != NULL) {
|
||||
int optbit=map_str_to_int(log_maskmap,logsdata->lines[0].val[0]);
|
||||
if (optbit < 0) {
|
||||
printfunc("debug option %s unknown\n",logsdata->lines[0].val[0]);
|
||||
} else {
|
||||
if(strcmp(logsdata->lines[0].val[1],"true")==0)
|
||||
SET_LOG_DEBUG(optbit);
|
||||
else
|
||||
CLEAR_LOG_DEBUG(optbit);
|
||||
if(strcmp(logsdata->lines[0].val[2],"true")==0)
|
||||
SET_LOG_DUMP(optbit);
|
||||
else
|
||||
CLEAR_LOG_DUMP(optbit);
|
||||
printfunc("%s debug %s dump %s\n",logsdata->lines[0].val[0],
|
||||
(strcmp(logsdata->lines[0].val[1],"true")==0)?"enabled":"disabled",
|
||||
(strcmp(logsdata->lines[0].val[2],"true")==0)?"enabled":"disabled");
|
||||
}
|
||||
}
|
||||
if (strcasestr(cmdbuff,"threadsched") != NULL) {
|
||||
unsigned int tid=strtoll(logsdata->lines[0].val[0],NULL,0);
|
||||
unsigned int core=strtoll(logsdata->lines[0].val[4],NULL,0);
|
||||
int priority=strtoll(logsdata->lines[0].val[6],NULL,0);
|
||||
printfunc("Thread %s id %u set affinity to core %u\n",logsdata->lines[0].val[0],tid,core);
|
||||
set_affinity( 0,(pid_t)tid, core) ;
|
||||
set_sched(0, (pid_t)tid, priority) ;
|
||||
}
|
||||
} else { /* end of set, => show */
|
||||
if (strcasestr(cmdbuff,"loglvl") != NULL) {
|
||||
|
||||
logsdata->numcols=4;
|
||||
logsdata->numlines=0;
|
||||
snprintf(logsdata->columns[0].coltitle,TELNET_CMD_MAXSIZE,"component");
|
||||
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
|
||||
snprintf(logsdata->columns[1].coltitle,TELNET_CMD_MAXSIZE,"level");
|
||||
logsdata->columns[1].coltype = TELNET_VARTYPE_STRING|TELNET_CHECKVAL_LOGLVL;
|
||||
snprintf(logsdata->columns[2].coltitle,TELNET_CMD_MAXSIZE,"enabled");
|
||||
logsdata->columns[2].coltype = TELNET_CHECKVAL_BOOL;
|
||||
snprintf(logsdata->columns[3].coltitle,TELNET_CMD_MAXSIZE,"in file");
|
||||
logsdata->columns[3].coltype = TELNET_CHECKVAL_BOOL;
|
||||
|
||||
|
||||
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
|
||||
if (g_log->log_component[i].name != NULL) {
|
||||
logsdata->numlines++;
|
||||
logsdata->lines[i].val[0]= (char *)(g_log->log_component[i].name);
|
||||
|
||||
logsdata->lines[i].val[1]=map_int_to_str(log_level_names,(g_log->log_component[i].level>=0)?g_log->log_component[i].level:g_log->log_component[i].savedlevel);
|
||||
logsdata->lines[i].val[2]=(g_log->log_component[i].level>=0)?"true":"false";
|
||||
logsdata->lines[i].val[3]=(g_log->log_component[i].filelog>0)?"true":"false";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strcasestr(cmdbuff,"dbgopt") != NULL) {
|
||||
webdatadef_t *logsdata = ( webdatadef_t *) data;
|
||||
logsdata->numcols=3;
|
||||
logsdata->numlines=0;
|
||||
snprintf(logsdata->columns[0].coltitle,TELNET_CMD_MAXSIZE,"module");
|
||||
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
|
||||
snprintf(logsdata->columns[1].coltitle,TELNET_CMD_MAXSIZE,"debug");
|
||||
logsdata->columns[1].coltype = TELNET_CHECKVAL_BOOL;
|
||||
snprintf(logsdata->columns[2].coltitle,TELNET_CMD_MAXSIZE,"dump");
|
||||
logsdata->columns[2].coltype = TELNET_CHECKVAL_BOOL;
|
||||
|
||||
for (int i=0; log_maskmap[i].name != NULL ; i++) {
|
||||
logsdata->numlines++;
|
||||
logsdata->lines[i].val[0]= log_maskmap[i].name;
|
||||
logsdata->lines[i].val[1]= (g_log->debug_mask & log_maskmap[i].value)?"true":"false";
|
||||
logsdata->lines[i].val[2]=(g_log->dump_mask & log_maskmap[i].value)?"true":"false";
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasestr(cmdbuff,"logopt") != NULL) {
|
||||
webdatadef_t *logsdata = ( webdatadef_t *) data;
|
||||
logsdata->numcols=2;
|
||||
logsdata->numlines=0;
|
||||
snprintf(logsdata->columns[0].coltitle,TELNET_CMD_MAXSIZE,"option");
|
||||
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
|
||||
snprintf(logsdata->columns[1].coltitle,TELNET_CMD_MAXSIZE,"enabled");
|
||||
logsdata->columns[1].coltype = TELNET_CHECKVAL_BOOL;
|
||||
|
||||
for (int i=0; log_options[i].name != NULL; i++) {
|
||||
logsdata->numlines++;
|
||||
logsdata->lines[i].val[0]=log_options[i].name;
|
||||
logsdata->lines[i].val[1]=(g_log->flag & log_options[i].value)?"true":"false";
|
||||
}
|
||||
}
|
||||
if (strcasestr(cmdbuff,"threadsched") != NULL) {
|
||||
proccmd_get_threaddata(cmdbuff, debug, prnt, ( webdatadef_t *) data);
|
||||
}
|
||||
} // show
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proccmd_show(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
|
||||
if (buf == NULL) {
|
||||
prnt("ERROR wrong softmodem SHOW command...\n");
|
||||
return 0;
|
||||
}
|
||||
if (debug > 0)
|
||||
prnt(" proccmd_show received %s\n",buf);
|
||||
if (strcasestr(buf,"thread") != NULL) {
|
||||
@@ -270,6 +466,10 @@ int bv1,bv2;
|
||||
int res;
|
||||
char sv1[64];
|
||||
|
||||
if (buf == NULL) {
|
||||
prnt("ERROR wrong thread command...\n");
|
||||
return 0;
|
||||
}
|
||||
bv1=0;
|
||||
bv2=0;
|
||||
sv1[0]=0;
|
||||
@@ -284,7 +484,7 @@ char sv1[64];
|
||||
prnt(" proccmd_thread: %i params = %i,%s,%i\n",res,bv1,sv1,bv2);
|
||||
if(res != 3)
|
||||
{
|
||||
prnt("softmodem thread needs 3 params, %i received\n",res);
|
||||
print_threads(buf, debug, prnt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -307,11 +507,20 @@ int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (debug > 0)
|
||||
prnt("process module received %s\n",buf);
|
||||
|
||||
end_configmodule();
|
||||
exit_fun("telnet server received exit command\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int proccmd_restart(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (debug > 0)
|
||||
prnt("process module received %s\n",buf);
|
||||
end_configmodule();
|
||||
configmodule_interface_t *cfg = config_get_if();
|
||||
execvpe(cfg->argv[0],cfg->argv ,environ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proccmd_log(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
@@ -396,7 +605,7 @@ int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
|
||||
SET_LOG_DUMP(optbit);
|
||||
else
|
||||
CLEAR_LOG_DUMP(optbit);
|
||||
proccmd_show("dbgopt",debug,prnt);
|
||||
proccmd_show("dump",debug,prnt);
|
||||
}
|
||||
}
|
||||
if (logparam != NULL) free(logparam);
|
||||
@@ -435,7 +644,7 @@ int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
|
||||
} else {
|
||||
prnt("%s%s unknown log sub command \n",logparam, tmpstr);
|
||||
}
|
||||
} else {
|
||||
} else {level=map_str_to_int(log_level_names,tmpstr);
|
||||
prnt("%s unknown log sub command \n",logsubcmd);
|
||||
}
|
||||
if (logparam != NULL) free(logparam);
|
||||
@@ -459,6 +668,7 @@ int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
|
||||
void add_softmodem_cmds(void)
|
||||
|
||||
@@ -44,9 +44,11 @@
|
||||
extern int proccmd_show(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_thread(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_restart(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_log(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_websrv_getdata(char *cmdbuff, int debug, void *data,telnet_printfunc_t prnt);
|
||||
telnetshell_vardef_t proc_vardef[] = {
|
||||
{"",0,NULL}
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
#define PROCCMD_LOG_HELP_STRING " log sub commands: \n\
|
||||
show: display current log configuration \n\
|
||||
@@ -65,18 +67,26 @@ telnetshell_vardef_t proc_vardef[] = {
|
||||
#define PROCCMD_THREAD_HELP_STRING " thread sub commands: \n\
|
||||
<thread id> aff <core> : set affinity of thread <thread id> to core <core> \n\
|
||||
<thread id> prio <prio> : set scheduling parameters for thread <thread id> \n\
|
||||
if prio < -20: linux scheduling policy set to FIFO, \n\
|
||||
with priority = -20 - prio \n\
|
||||
if prio > 19: linux scheduling policy set to OTHER, \n\
|
||||
with priority (nice value) = prio \n\
|
||||
-100 < prio < 0: linux scheduling policy set to FIFO, priority -prio, \n\
|
||||
-200 < prio < -100: linux scheduling policy set to RR, priority -(prio+100), \n\
|
||||
0 <= prio < 40: linux scheduling policy set to NORMAL, nice value prio-20 \n\
|
||||
40 <= prio < 80: linux scheduling policy set to BATCH, nice value prio-60 \n\
|
||||
prio >=80: linux scheduling policy set to IDLE \n\
|
||||
use \"softmodem show thread\" to get <thread id> \n"
|
||||
|
||||
|
||||
telnetshell_cmddef_t proc_cmdarray[] = {
|
||||
{"show","loglvl|thread|config", proccmd_show},
|
||||
{"log","(enter help for details)", proccmd_log},
|
||||
{"thread","(enter help for details)", proccmd_thread},
|
||||
{"exit","", proccmd_exit},
|
||||
{"show","loglvl|thread|config", proccmd_show,{(webfunc_t)proccmd_websrv_getdata},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"log","(enter help for details)", proccmd_log, {NULL},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"show loglvl","", proccmd_log,{(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_GETWEBTBLDATA,NULL},
|
||||
{"show logopt","", proccmd_log,{(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_GETWEBTBLDATA,NULL},
|
||||
{"show dbgopt","", proccmd_log,{(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_GETWEBTBLDATA,NULL},
|
||||
{"show config","", proccmd_show,{(webfunc_t)proccmd_show}, TELNETSRV_CMDFLAG_WEBSRVONLY,NULL},
|
||||
{"show thread","", proccmd_thread,{(webfunc_t)proccmd_show},TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_AUTOUPDATE,NULL},
|
||||
{"thread","(enter help for details)",proccmd_thread,{NULL},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"show threadsched","",proccmd_show,{(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_GETWEBTBLDATA,NULL},
|
||||
{"exit","", proccmd_exit,{NULL},TELNETSRV_CMDFLAG_CONFEXEC,NULL},
|
||||
{"restart","",proccmd_restart,{NULL},TELNETSRV_CMDFLAG_CONFEXEC,NULL},
|
||||
{"","",NULL},
|
||||
};
|
||||
#else
|
||||
|
||||
7
common/utils/websrv/DOC/websrv.md
Normal file
7
common/utils/websrv/DOC/websrv.md
Normal file
@@ -0,0 +1,7 @@
|
||||
The oai web server is an optional monitoring and debugging tool. It gives access to the same functionalities as the telnet server via a web interface
|
||||
|
||||
* [Using the web server](webserverusage.md)
|
||||
* [enhancing the webserver](webserverdevcmd.md)
|
||||
* [web server architecture ](webserverarch.md)
|
||||
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
31
common/utils/websrv/DOC/websrvarch.md
Normal file
31
common/utils/websrv/DOC/websrvarch.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# telnet server principles
|
||||
|
||||
The oai telnet server is implemented in shared libraries to be loaded by the [oai shared library loader](loader). `libtelnetsrv.so ` contains the code common to all oai softmodem executables, where `libtelnetsrv_<app>.so` contains the code specific to the executable identified by `app`.
|
||||
|
||||
| `<app>` | executable |
|
||||
| :-----: | :---------------: |
|
||||
| enb | `lte-softmodem` |
|
||||
| gnb | `nr-softmodem` |
|
||||
| 4Gue | `lte-uesoftmodem` |
|
||||
| 5Gue | `nr-uesoftmodem` |
|
||||
|
||||
The implementation includes a `telnetsrv_autoinit` function which is automatically called at load time, starts the telnet server and registers a first set of commands, which are delivered with the server (telnet, softmodem, loader). it also uses the `get_softmodem_function` call to retrieve the running executable id and possibly loads the corresponding `libtelnetsrv_<app>.so`library.
|
||||
|
||||
Currently the telnet server only supports one user connection. The same dedicated thread is used to wait for a user connection and process the input received from this connection.
|
||||
|
||||
The telnet server provides an API which can be used by any oai component to add new CLI commands to the server. A pre-defined command can be used to get or set a list of variables.
|
||||
|
||||
|
||||
|
||||
# telnet server source files
|
||||
|
||||
telnet server source files are located in [common/utils/telnetsrv](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv)
|
||||
|
||||
1. [telnetsrv.c](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.c) contains the telnet server implementation, including the implementation of the `telnet` CLI command. This implementation is compatible with all softmodem executables and is in charge of loading any additional `libtelnetsrv_<app> .so` containing code specific to the running executables.
|
||||
1. [telnetsrv.h](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.h) is the telnet server include file containing both private and public data type definitions. It also contains API prototypes for functions that are used to register a new command in the server.
|
||||
1. `telnetsrv_<XXX\>.c`: implementation of \<XXX\> CLI command which are delivered with the telnet server and are common to all softmodem executables.
|
||||
1. `telnetsrv_<XXX\>.h`: include file for the implementation of XXX CLI command. Usually included only in the corresponding `.c`file
|
||||
1. `telnetsrv_<app>_<XXX>.c`: implementation of \<XXX\> CLI command specific to the executable identified by \<app\>.These sources are used to create `libtelnetsrv_<app>.so` at build time.
|
||||
1. [telnetsrv_CMakeLists.txt](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/telnetsrv/telnetsrv_CMakeLists.txt): CMakelists file containing the cmake instructions to build the telnet server. this file is included in the [global oai CMakelists](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/cmake_targets/CMakeLists.txt).
|
||||
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
40
common/utils/websrv/DOC/websrvuse.md
Normal file
40
common/utils/websrv/DOC/websrvuse.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# starting the softmodem with the telnet server
|
||||
By default the embedded telnet server, which is implemented in a shared library, is not built. It can be built after compiling the softmodem executable using the `build_oai` script:
|
||||
|
||||
```bash
|
||||
cd \<oai repository\>/openairinterface5g
|
||||
source oaienv
|
||||
cd cmake_targets
|
||||
./build_oai --build-lib telnetsrv
|
||||
```
|
||||
|
||||
This will create the `libtelnetsrv.so` and `libtelnetsrv_<app> file in the `targets/bin` and `cmake_targets/ran_build/build` sub directories of the oai repository. <app> can be "enb", "gnb", "4GUE" or "5GUE", each library containing functions specific to a given executable.
|
||||
|
||||
When starting the softmodem, you must specify the **_\-\-telnetsrv_** option to load and start the telnet server. The telnet server is loaded via the [oai shared library loader](loader).
|
||||
|
||||
# using the Command Line Interface
|
||||
By default the telnet server listen on all the ip addresses configured on the system and on port 9090. This behavior can be changed using the `listenaddr` and `listenport` parameters.
|
||||
The telnet server includes a basic help, listing available commands and some commands also provide a specific detailed help sub-command.
|
||||
Below are examples of telnet sessions:
|
||||
|
||||
* [getting help](telnethelp.md)
|
||||
* [using the history](telnethist.md)
|
||||
* [using the get and set commands](telnetgetset.md)
|
||||
* [using the loop command](telnetloop.md)
|
||||
* [loader command](telnetloader.md)
|
||||
* [log command](telnetlog.md)
|
||||
* [measur command](telnetmeasur.md)
|
||||
|
||||
# telnet server parameters
|
||||
The telnet server is using the [oai configuration module](Config/Rtusage). Telnet parameters must be specified in the `telnetsrv` section. Some parameters can be modified via the telnet telnet server command, as specified in the last column of the following table.
|
||||
|
||||
| name | type | default | description | dynamic |
|
||||
|:---:|:---:|:---:|:----|:----:|
|
||||
| `listenaddr` | `ipV4 address, ascii format` | "0.0.0.0" | local address the server is listening on| N |
|
||||
| `listenport` | `integer` | 9090 | port number the server is listening on | N |
|
||||
| `loopcount` | `integer` | 10 | number of iterations for the loop command | Y |
|
||||
| `loopdelay` | `integer` | 5000 | delay (in ms) between 2 loop command iterations | Y |
|
||||
| `histfile` | `character string` | "oaitelnet.history" | file used for command history persistency | Y |
|
||||
| `histfsize` | `integer` | 50 | maximum number of commands saved in the history | Y |
|
||||
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
17
common/utils/websrv/frontend/.browserslistrc
Normal file
17
common/utils/websrv/frontend/.browserslistrc
Normal file
@@ -0,0 +1,17 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||
16
common/utils/websrv/frontend/.editorconfig
Normal file
16
common/utils/websrv/frontend/.editorconfig
Normal file
@@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
50
common/utils/websrv/frontend/.eslintrc.json
Normal file
50
common/utils/websrv/frontend/.eslintrc.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"projects/**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts"
|
||||
],
|
||||
"parserOptions": {
|
||||
"project": [
|
||||
"common/utils/websrv/frontend/tsconfig.json"
|
||||
],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "app",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": "app",
|
||||
"style": "kebab-case"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.html"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
50
common/utils/websrv/frontend/.gitignore
vendored
Normal file
50
common/utils/websrv/frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/artifacts
|
||||
/builds
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events*.json
|
||||
speed-measure-plugin*.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.angular/cache
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
config.toml
|
||||
1
common/utils/websrv/frontend/README.md
Normal file
1
common/utils/websrv/frontend/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# SoftModemNgx
|
||||
108
common/utils/websrv/frontend/angular.json
Normal file
108
common/utils/websrv/frontend/angular.json
Normal file
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"cli": {
|
||||
"analytics": false,
|
||||
"schematicCollections": [
|
||||
"@angular-eslint/schematics"
|
||||
]
|
||||
},
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"softmodemngx": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:application": {
|
||||
"strict": true
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/softmodem-ngx",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/purple-green.css",
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"allowedCommonJsDependencies": [
|
||||
"@firebase/auth",
|
||||
"firebase"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "1.5mb",
|
||||
"maximumError": "2mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "softmodemngx:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "softmodemngx:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "softmodemngx:build"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
common/utils/websrv/frontend/e2e/protractor-ci.conf.js
Normal file
40
common/utils/websrv/frontend/e2e/protractor-ci.conf.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
chromeOptions: {
|
||||
args: ['--headless', '--no-sandbox']
|
||||
}
|
||||
},
|
||||
directConnect: true,
|
||||
SELENIUM_PROMISE_MANAGER: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function () { }
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({
|
||||
spec: {
|
||||
displayStacktrace: StacktraceOption.PRETTY
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
37
common/utils/websrv/frontend/e2e/protractor.conf.js
Normal file
37
common/utils/websrv/frontend/e2e/protractor.conf.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
SELENIUM_PROMISE_MANAGER: false,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function () { }
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({
|
||||
spec: {
|
||||
displayStacktrace: StacktraceOption.PRETTY
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
23
common/utils/websrv/frontend/e2e/src/app.e2e-spec.ts
Normal file
23
common/utils/websrv/frontend/e2e/src/app.e2e-spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { browser, logging } from 'protractor';
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
// it('should display welcome message', async () => {
|
||||
// await page.navigateTo();
|
||||
// expect(await page.getTitleText()).toEqual('example app is running!');
|
||||
// });
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry));
|
||||
});
|
||||
});
|
||||
11
common/utils/websrv/frontend/e2e/src/app.po.ts
Normal file
11
common/utils/websrv/frontend/e2e/src/app.po.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
async navigateTo(): Promise<unknown> {
|
||||
return browser.get(browser.baseUrl);
|
||||
}
|
||||
|
||||
async getTitleText(): Promise<string> {
|
||||
return element(by.css('app-root .content span')).getText();
|
||||
}
|
||||
}
|
||||
10
common/utils/websrv/frontend/e2e/tsconfig.json
Normal file
10
common/utils/websrv/frontend/e2e/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es2018",
|
||||
"types": ["jasmine", "node"]
|
||||
}
|
||||
}
|
||||
24319
common/utils/websrv/frontend/package-lock.json
generated
Normal file
24319
common/utils/websrv/frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
65
common/utils/websrv/frontend/package.json
Normal file
65
common/utils/websrv/frontend/package.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "softmodemngx",
|
||||
"version": "2.0.0",
|
||||
"scripts": {
|
||||
"lint": "ng lint",
|
||||
"build": "ng build",
|
||||
"dev": "ng serve --configuration=development",
|
||||
"prod": "ng serve --configuration=production"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular-slider/ngx-slider": "^2.0.4",
|
||||
"@angular/animations": "^14.1.0",
|
||||
"@angular/cdk": "^14.1.0",
|
||||
"@angular/common": "^14.1.0",
|
||||
"@angular/compiler": "^14.1.0",
|
||||
"@angular/core": "^14.1.0",
|
||||
"@angular/flex-layout": "^14.0.0-beta.40",
|
||||
"@angular/forms": "^14.1.0",
|
||||
"@angular/material": "^14.1.0",
|
||||
"@angular/platform-browser": "^14.1.0",
|
||||
"@angular/platform-browser-dynamic": "^14.1.0",
|
||||
"@angular/router": "^14.1.0",
|
||||
"chart.js": "^3.8.2",
|
||||
"moment": "^2.29.3",
|
||||
"ng2-charts": "^4.0.0",
|
||||
"rxjs": "^6.6.6",
|
||||
"tslib": "^2.0.0",
|
||||
"zone.js": "^0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/architect": "^0.1401.0",
|
||||
"@angular-devkit/build-angular": "^14.1.0",
|
||||
"@angular-eslint/builder": "14.0.2",
|
||||
"@angular-eslint/eslint-plugin": "14.0.2",
|
||||
"@angular-eslint/eslint-plugin-template": "14.0.2",
|
||||
"@angular-eslint/schematics": "14.0.2",
|
||||
"@angular-eslint/template-parser": "14.0.2",
|
||||
"@angular/cli": "^14.1.0",
|
||||
"@angular/compiler-cli": "^14.1.0",
|
||||
"@angular/language-service": "^14.1.0",
|
||||
"@types/node": "^12.20.23",
|
||||
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
||||
"@typescript-eslint/parser": "^5.29.0",
|
||||
"eslint": "^8.18.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"fuzzy": "^0.1.3",
|
||||
"husky": "^5.1.3",
|
||||
"inquirer": "^6.2.2",
|
||||
"inquirer-autocomplete-prompt": "^1.0.1",
|
||||
"jasmine-core": "~3.7.1",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"open": "^7.0.3",
|
||||
"ts-node": "^8.10.2",
|
||||
"tslint-angular": "^3.0.3",
|
||||
"typescript": "~4.6.4"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged && ng lint && ng test",
|
||||
"pre-push": "ng build --aot true"
|
||||
}
|
||||
}
|
||||
}
|
||||
116
common/utils/websrv/frontend/src/app/api/commands.api.ts
Normal file
116
common/utils/websrv/frontend/src/app/api/commands.api.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from 'src/environments/environment';
|
||||
export interface IInfo {
|
||||
name: string;
|
||||
value: string;
|
||||
type: IArgType;
|
||||
modifiable: boolean; //set command ?
|
||||
}
|
||||
|
||||
export interface IModule {
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
||||
export enum ILogLvl {
|
||||
error = "error",
|
||||
warn = "warn",
|
||||
analysis = "analysis",
|
||||
info = "info",
|
||||
debug = "debug",
|
||||
trace = "trace"
|
||||
}
|
||||
|
||||
export enum ILogOutput {
|
||||
stdout = "stdout",
|
||||
telnet = "telnet",
|
||||
web = "web",
|
||||
file = "/tmp/<component>.log",
|
||||
}
|
||||
|
||||
export enum IArgType {
|
||||
boolean = "boolean",
|
||||
list = "list",
|
||||
loglvl = "loglvl",
|
||||
range = "range",
|
||||
number = "number",
|
||||
string = "string",
|
||||
configfile = "configfile",
|
||||
simuTypes = "simuTypes",
|
||||
}
|
||||
|
||||
export enum ICommandOptions {
|
||||
update = "update", // result can be updated, triggers update button on result page when set
|
||||
}
|
||||
|
||||
export interface IVariable {
|
||||
name: string;
|
||||
value: string;
|
||||
type: IArgType;
|
||||
modifiable: boolean; //set command ?
|
||||
}
|
||||
|
||||
export interface ICommand {
|
||||
name: string;
|
||||
confirm?: string;
|
||||
question?: IQuestion;
|
||||
param?: IVariable;
|
||||
options?: ICommandOptions[];
|
||||
}
|
||||
export interface ITable {
|
||||
columns: IColumn[];
|
||||
rows: string[];
|
||||
}
|
||||
export interface IQuestion {
|
||||
display: string;
|
||||
pname: string;
|
||||
type: IArgType;
|
||||
}
|
||||
export interface IResp {
|
||||
display: string[],
|
||||
table?: ITable
|
||||
}
|
||||
|
||||
export interface IParam {
|
||||
value: string,
|
||||
col: IColumn
|
||||
}
|
||||
|
||||
export interface IColumn { //should use IVariable ?
|
||||
name: string;
|
||||
type: IArgType;
|
||||
modifiable: boolean; //set command ?
|
||||
}
|
||||
export interface IRow {
|
||||
params: IParam[],
|
||||
rawIndex: number,
|
||||
cmdName: string
|
||||
}
|
||||
|
||||
|
||||
export const route = 'oaisoftmodem/';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class CommandsApi {
|
||||
constructor(private httpClient: HttpClient) { }
|
||||
|
||||
public readInfos$ = () => this.httpClient.get<IInfo[]>('http://' + environment.backend + route + 'variables/');
|
||||
|
||||
public setInfo$ = (info: IInfo) => this.httpClient.post<IResp>('http://' + environment.backend + route + 'variables/', info);
|
||||
|
||||
public readModules$ = () => this.httpClient.get<IModule[]>('http://' + environment.backend + route + 'commands/');
|
||||
|
||||
public readVariables$ = (moduleName: string) => this.httpClient.get<IInfo[]>('http://' + environment.backend + route + moduleName + '/variables/');
|
||||
|
||||
public readCommands$ = (moduleName: string) => this.httpClient.get<ICommand[]>('http://' + environment.backend + route + moduleName + '/commands/');
|
||||
|
||||
public runCommand$ = (command: ICommand, moduleName: string) => this.httpClient.post<IResp>('http://' + environment.backend + route + moduleName + '/commands/', command);
|
||||
|
||||
public setCmdVariable$ = (variable: IInfo, moduleName: string) => this.httpClient.post<IResp>('http://' + environment.backend + route + moduleName + '/variables/', variable);
|
||||
|
||||
public setCmdParams$ = (row: IRow, moduleName: string) => this.httpClient.post<IResp>('http://' + environment.backend + route + moduleName + '/set/', row);
|
||||
|
||||
}
|
||||
47
common/utils/websrv/frontend/src/app/api/scope.api.ts
Normal file
47
common/utils/websrv/frontend/src/app/api/scope.api.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
export enum IScopeGraphType {
|
||||
IQs = "IQs",
|
||||
LLR = "LLR",
|
||||
WF = "WF",
|
||||
UNSUP = "UNSUP"
|
||||
}
|
||||
|
||||
export interface IGraphDesc {
|
||||
title: string;
|
||||
type: IScopeGraphType;
|
||||
id: number;
|
||||
srvidx: number;
|
||||
}
|
||||
|
||||
export interface IScopeDesc {
|
||||
title: string;
|
||||
graphs: IGraphDesc[];
|
||||
}
|
||||
|
||||
export interface IScopeCmd {
|
||||
name: string;
|
||||
graphid?: number; // the graph srvidx
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface ISigDesc {
|
||||
target_id: number;
|
||||
antenna_id: number;
|
||||
}
|
||||
|
||||
const route = 'oaisoftmodem/scopectrl/';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ScopeApi {
|
||||
constructor(private httpClient: HttpClient) { }
|
||||
|
||||
public getScopeInfos$ = () => this.httpClient.get<IScopeDesc>('http://' + environment.backend + route);
|
||||
|
||||
public setScopeParams$ = (cmd: IScopeCmd) => this.httpClient.post('http://' + environment.backend + route, cmd);
|
||||
|
||||
}
|
||||
16
common/utils/websrv/frontend/src/app/app-routing.module.ts
Normal file
16
common/utils/websrv/frontend/src/app/app-routing.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { AppComponent } from './app.component';
|
||||
import { CommandsComponent } from './components/commands/commands.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: '/websrv', pathMatch: 'full' },
|
||||
{ path: 'websrv', component: AppComponent },
|
||||
{ path: '**', redirectTo: '' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
11
common/utils/websrv/frontend/src/app/app.component.css
Normal file
11
common/utils/websrv/frontend/src/app/app.component.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.mat-tab-group {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.mat-ink-bar{
|
||||
height: 8px !important;
|
||||
}
|
||||
.mat-tab-label-active
|
||||
{
|
||||
color: #000000 !important;
|
||||
}
|
||||
|
||||
11
common/utils/websrv/frontend/src/app/app.component.html
Normal file
11
common/utils/websrv/frontend/src/app/app.component.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<mat-tab-group backgroundColor="primary" color="accent">
|
||||
<mat-tab label="Commands">
|
||||
<app-commands></app-commands>
|
||||
</mat-tab>
|
||||
<mat-tab label={{scopelabel}} disabled={{!isscopeavailable}}>
|
||||
<app-scope (ScopeEnabled)="onScopeEnabled($event)"></app-scope>
|
||||
</mat-tab>
|
||||
<mat-tab label="Logger">
|
||||
<app-logger></app-logger>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
22
common/utils/websrv/frontend/src/app/app.component.ts
Normal file
22
common/utils/websrv/frontend/src/app/app.component.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css'],
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'oai softmodem';
|
||||
isscopeavailable = false;
|
||||
scopelabel = '';
|
||||
constructor() {
|
||||
this.scopelabel = '';
|
||||
this.isscopeavailable=false;
|
||||
}
|
||||
|
||||
onScopeEnabled( enabled: boolean) {
|
||||
this.isscopeavailable= enabled;
|
||||
this.scopelabel= enabled ? 'Scope' : '';
|
||||
}
|
||||
}
|
||||
88
common/utils/websrv/frontend/src/app/app.module.ts
Normal file
88
common/utils/websrv/frontend/src/app/app.module.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatSliderModule } from '@angular/material/slider';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NgChartsModule } from 'ng2-charts';
|
||||
import { CommandsApi } from './api/commands.api';
|
||||
import { ScopeApi } from './api/scope.api';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { CommandsComponent } from './components/commands/commands.component';
|
||||
import { ConfirmDialogComponent } from './components/confirm/confirm.component';
|
||||
import { DialogComponent } from './components/dialog/dialog.component';
|
||||
import { QuestionDialogComponent } from './components/question/question.component';
|
||||
import { ScopeComponent } from './components/scope/scope.component';
|
||||
import { InterceptorProviders } from './interceptors/interceptors';
|
||||
import { LoadingService } from './services/loading.service';
|
||||
import { WebSocketService } from './services/websocket.service';
|
||||
import { LoggerComponent } from './components/logger/logger.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
CommandsComponent,
|
||||
ConfirmDialogComponent,
|
||||
QuestionDialogComponent,
|
||||
DialogComponent,
|
||||
ScopeComponent,
|
||||
LoggerComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientModule,
|
||||
MatButtonModule,
|
||||
FlexLayoutModule,
|
||||
MatDialogModule,
|
||||
DragDropModule,
|
||||
MatSliderModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatChipsModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatToolbarModule,
|
||||
MatTableModule,
|
||||
MatListModule,
|
||||
MatSelectModule,
|
||||
MatSnackBarModule,
|
||||
MatSlideToggleModule,
|
||||
MatGridListModule,
|
||||
MatCardModule,
|
||||
MatTabsModule,
|
||||
NgChartsModule,
|
||||
],
|
||||
providers: [
|
||||
// services
|
||||
LoadingService,
|
||||
WebSocketService,
|
||||
// api
|
||||
CommandsApi,
|
||||
ScopeApi,
|
||||
// interceptors
|
||||
InterceptorProviders,
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
@@ -0,0 +1,127 @@
|
||||
<div class="grid-container" >
|
||||
<mat-grid-list cols="2" rowHeight="15vh" >
|
||||
<mat-grid-tile [colspan]="1" [rowspan]="2" >
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header >
|
||||
<mat-card-title>Connection info</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div *ngIf="infos$ | async as infos">
|
||||
<div class="spaceddiv" *ngFor="let info of infos">
|
||||
<mat-form-field class="scrollablefield" >
|
||||
<mat-label>{{ info.nameFC.value }}</mat-label>
|
||||
<input matInput [formControl]="info.valueFC" [readonly]="!info.modifiableFC.value" />
|
||||
</mat-form-field>
|
||||
<button mat-raised-button color="primary" [disabled]="!info.modifiableFC.value"
|
||||
(click)="onInfoSubmit(info)">
|
||||
{{ info.btnTxtFC }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
<mat-grid-tile [colspan]="1" [rowspan]="2">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Softmodem commands</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div class="spaceddiv" *ngIf="modules$ | async as modules" fxLaypout="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Module</mat-label>
|
||||
<mat-select (selectionChange)="onModuleSelect($event.value)" [(value)]="selectedModule">
|
||||
<mat-option *ngFor="let module of modules" [value]="module"> {{ module.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div *ngIf="cmds$ | async as cmds">
|
||||
<div *ngIf="cmds.length">
|
||||
<mat-chip-list>
|
||||
<mat-chip *ngFor="let cmd of cmds" (click)="onCmdSubmit(cmd)"> {{cmd.nameFC.value}}
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
<mat-grid-tile *ngIf="vars$ | async as vars" [colspan]="1" [rowspan]="4">
|
||||
<mat-card *ngIf="vars.length" class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ selectedModule!.name }} variables</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div class="spaceddiv" *ngFor="let variable of vars">
|
||||
<mat-form-field class="scrollablefield">
|
||||
<mat-label>{{ variable.nameFC.value }}</mat-label>
|
||||
<input matInput [formControl]="variable.valueFC" [readonly]="!variable.modifiableFC.value" />
|
||||
</mat-form-field>
|
||||
<button mat-raised-button color="primary" [disabled]="!variable.modifiableFC.value"
|
||||
(click)="onVarsubmit(variable)">
|
||||
set
|
||||
</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
<mat-grid-tile *ngIf="(rows$ | async)?.length" [colspan]="1" [rowspan]="4">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ selectedModule!.name }} {{ selectedCmd!.name }} </mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div >
|
||||
<mat-table mat-table [dataSource]="rows$" multiTemplateDataRows class="mat-elevation-z8">
|
||||
|
||||
<div class="TableRowdiv" *ngFor="let col of columns; index as colIndex" matColumnDef="{{col.name}}">
|
||||
<mat-header-cell *matHeaderCellDef fxLayoutAlign="start center">
|
||||
<div>
|
||||
<h4>{{ col.name }}</h4>
|
||||
</div>
|
||||
</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<div [ngSwitch]="col.type" [formGroup]="row" fxLayoutAlign="start center">
|
||||
<mat-slide-toggle *ngSwitchCase="IArgType.boolean" [formControl]="row.paramsCtrls[colIndex].valueFC"
|
||||
[checked]="row.paramsCtrls[colIndex].valueFC.value">
|
||||
</mat-slide-toggle>
|
||||
<mat-list-item role="listitem">
|
||||
<mat-form-field *ngSwitchCase="IArgType.loglvl">
|
||||
<mat-select [formControl]="row.paramsCtrls[colIndex].valueFC"
|
||||
[(value)]="row.paramsCtrls[colIndex].valueFC.value">
|
||||
<mat-option *ngFor="let level of logLvlValues" [value]="level"> {{ level }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</mat-list-item>
|
||||
<div *ngSwitchDefault>
|
||||
<mat-form-field>
|
||||
<input matInput [formControl]="row.paramsCtrls[colIndex].valueFC" [readonly]="!col.modifiable" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</mat-cell>
|
||||
</div>
|
||||
|
||||
<div matColumnDef="button">
|
||||
<mat-header-cell *matHeaderCellDef> </mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" fxLayoutAlign="center">
|
||||
<button class="TableBtn" mat-raised-button color="primary" (click)="onParamSubmit(row)" [disabled]="row.pristine"> set
|
||||
</button>
|
||||
</mat-cell>
|
||||
</div>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
|
||||
|
||||
</mat-table>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
</mat-grid-list>
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
.spaceddiv {
|
||||
height: 45px;
|
||||
width: 40vw;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 0 auto;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.TableRowdiv {
|
||||
height: 38px;
|
||||
display: flex;
|
||||
/* justify-content: space-between;*/
|
||||
margin: 2px;
|
||||
width: 95%;
|
||||
.item:nth-child(1n){
|
||||
width: 10%;
|
||||
}
|
||||
.item {
|
||||
width: 4%;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
.TableBtn {
|
||||
height: 25px;
|
||||
width: 35p;
|
||||
display:flex;
|
||||
padding-bottom:8px;
|
||||
}
|
||||
|
||||
.TableText {
|
||||
display: flex;
|
||||
width: 8em;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.scrollablefield {
|
||||
width: 80%;
|
||||
height: 20px;
|
||||
.mat-input-element {
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-card {
|
||||
height: 95%;
|
||||
overflow-y: auto;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.status {
|
||||
color: green;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.ng-invalid .status {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.dashboard-card {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
}
|
||||
|
||||
.more-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.dashboard-card-content {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { UntypedFormArray } from '@angular/forms';
|
||||
import { BehaviorSubject, forkJoin, timer } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { of } from 'rxjs';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { CommandsApi, IArgType, IColumn, ICommand, IInfo, ILogLvl, IParam, IRow } from 'src/app/api/commands.api';
|
||||
import { CmdCtrl } from 'src/app/controls/cmd.control';
|
||||
import { InfoCtrl } from 'src/app/controls/info.control';
|
||||
import { ModuleCtrl } from 'src/app/controls/module.control';
|
||||
import { RowCtrl } from 'src/app/controls/row.control';
|
||||
import { VarCtrl } from 'src/app/controls/var.control';
|
||||
import { DialogService } from 'src/app/services/dialog.service';
|
||||
import { DownloadService } from 'src/app/services/download.service';
|
||||
import { LoadingService } from 'src/app/services/loading.service';
|
||||
import { ViewEncapsulation } from '@angular/core';
|
||||
|
||||
const CHANNEL_MOD_MODULE = "channelmod"
|
||||
const PREDEF_CMD = "show predef"
|
||||
|
||||
@Component({
|
||||
selector: 'app-commands',
|
||||
templateUrl: './commands.component.html',
|
||||
styleUrls: ['./commands.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class CommandsComponent {
|
||||
|
||||
IArgType = IArgType;
|
||||
logLvlValues = Object.values(ILogLvl)
|
||||
|
||||
// softmodem
|
||||
infos$: Observable<VarCtrl[]>
|
||||
modules$: Observable<ModuleCtrl[]>
|
||||
|
||||
// module
|
||||
selectedModule?: ModuleCtrl
|
||||
vars$?: Observable<VarCtrl[]>
|
||||
cmds$?: Observable<CmdCtrl[]>
|
||||
|
||||
// command
|
||||
selectedCmd?: ICommand
|
||||
displayedColumns: string[] = []
|
||||
rows$: BehaviorSubject<RowCtrl[]> = new BehaviorSubject<RowCtrl[]>([])
|
||||
columns: IColumn[] = []
|
||||
|
||||
constructor(
|
||||
public commandsApi: CommandsApi,
|
||||
public loadingService: LoadingService,
|
||||
public dialogService: DialogService,
|
||||
public downloadService: DownloadService,
|
||||
|
||||
) {
|
||||
this.infos$ = this.commandsApi.readInfos$().pipe(
|
||||
map((infos) => infos.map(info => new InfoCtrl(info)))
|
||||
);
|
||||
|
||||
this.modules$ = this.commandsApi.readModules$().pipe(
|
||||
map(imodules => imodules.map(imodule => new ModuleCtrl(imodule))),
|
||||
filter(controls => controls.length > 0),
|
||||
tap(controls => this.onModuleSelect(controls[0]))
|
||||
);
|
||||
}
|
||||
|
||||
// get types$() {
|
||||
// return this.modules$.pipe(
|
||||
// filter(modules => modules.map(module => module.name).includes(CHANNEL_MOD_MODULE)),
|
||||
// mergeMap(modules => this.commandsApi.readCommands$(modules[0]!.name)),
|
||||
// map(icmds => icmds.filter(cmd => cmd.name === PREDEF_CMD)),
|
||||
// filter(icmds => icmds.length > 0),
|
||||
// map(icmds => new CmdCtrl(icmds[0])),
|
||||
// mergeMap(control => this.commandsApi.runCommand$(control.api(), CHANNEL_MOD_MODULE)),
|
||||
// map(resp => resp.display.map(line => line.match('/\s*[0-9]*\s*(\S*)\n/gm')![0])),
|
||||
// tap(types => console.log(types.join(', ')))
|
||||
// );
|
||||
// }
|
||||
|
||||
onInfoSubmit(control: InfoCtrl) {
|
||||
let info: IInfo = control.api();
|
||||
|
||||
if (info.type === IArgType.configfile) {
|
||||
this.downloadService.getFile(info.value)
|
||||
} else {
|
||||
this.commandsApi.setInfo$(info).subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
onModuleSelect(module: ModuleCtrl) {
|
||||
|
||||
this.selectedModule = module
|
||||
this.selectedCmd = undefined
|
||||
|
||||
this.cmds$ = this.commandsApi.readCommands$(module.name).pipe(
|
||||
map(icmds => icmds.map(icmd => new CmdCtrl(icmd))),
|
||||
map(cmds => {
|
||||
module.cmdsFA = new UntypedFormArray(cmds)
|
||||
return module.cmdsFA.controls as CmdCtrl[]
|
||||
})
|
||||
)
|
||||
|
||||
this.vars$ = this.commandsApi.readVariables$(module.name).pipe(
|
||||
map(ivars => ivars.map(ivar => new VarCtrl(ivar))),
|
||||
map(vars => {
|
||||
module.varsFA = new UntypedFormArray(vars)
|
||||
return module.varsFA.controls as VarCtrl[]
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
onVarsubmit(control: VarCtrl) {
|
||||
this.commandsApi.setCmdVariable$(control.api(), this.selectedModule!.name)
|
||||
.pipe(
|
||||
map(resp => this.dialogService.openVarRespDialog(resp))
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
onCmdSubmit(control: CmdCtrl) {
|
||||
|
||||
this.selectedCmd = control.api()
|
||||
|
||||
const obsparam$ = forkJoin([control.confirm
|
||||
? this.dialogService.openConfirmDialog(control.confirm)
|
||||
: control.question
|
||||
? this.dialogService.openQuestionDialog(this.selectedModule! + " " + this.selectedModule!.name, control)
|
||||
: of(true)]);
|
||||
|
||||
obsparam$.pipe(
|
||||
switchMap(results => {
|
||||
if (!results[0])
|
||||
return of(null);
|
||||
if (control.isResUpdatable())
|
||||
control.ResUpdTimer = timer(2000, 1000);
|
||||
return this.execCmd$(control);
|
||||
}))
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private execCmd$(control: CmdCtrl) {
|
||||
if (control.isResUpdatable() && control.ResUpdTimer) {
|
||||
if (!(control.ResUpdTimerSubscriber)) {
|
||||
control.ResUpdTimerSubscriber = control.ResUpdTimer.subscribe(iteration => {
|
||||
console.log("Update timer fired" + iteration);
|
||||
if (control.updbtnname === "Stop update")
|
||||
this.execCmd$(control);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.commandsApi.runCommand$(control!.api(), this.selectedModule!.name).subscribe(resp => {
|
||||
if (resp.display[0]) this.dialogService.updateCmdDialog(control, resp, 'cmd ' + control.nameFC.value + ' response:')
|
||||
// else return of(resp)
|
||||
|
||||
const controls: RowCtrl[] = []
|
||||
this.displayedColumns = []
|
||||
|
||||
if (resp.table) {
|
||||
this.columns = resp.table.columns
|
||||
this.displayedColumns = this.columns.map(col => col.name)
|
||||
this.displayedColumns.push('button')
|
||||
|
||||
for (let rawIndex = 0; rawIndex < resp.table.rows.length; rawIndex++) {
|
||||
|
||||
let params: IParam[] = []
|
||||
for (let i = 0; i < this.columns.length; i = i + 1) {
|
||||
params.push({
|
||||
value: resp.table.rows[rawIndex][i],
|
||||
col: this.columns[i]
|
||||
})
|
||||
}
|
||||
|
||||
const irow: IRow = {
|
||||
params: params,
|
||||
rawIndex: rawIndex,
|
||||
cmdName: this.selectedCmd!.name
|
||||
}
|
||||
|
||||
controls[rawIndex] = new RowCtrl(irow)
|
||||
}
|
||||
}
|
||||
this.rows$.next(controls)
|
||||
},
|
||||
err => console.error('execCmd error: ' + err),
|
||||
() => console.log('execCmd completed: '),
|
||||
) // map resp
|
||||
|
||||
|
||||
return of(null);
|
||||
}
|
||||
|
||||
onParamSubmit(control: RowCtrl) {
|
||||
this.commandsApi.setCmdParams$(control.api(), this.selectedModule!.name).subscribe(() => this.execCmd$(new CmdCtrl(this.selectedCmd!)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<h3>{{ data.title }}</h3>
|
||||
<div fxLayoutGap="10px" mat-dialog-actions fxLayout="row" fxLayoutAlign="center start">
|
||||
<button mat-button [mat-dialog-close]="true" cdkFocusInitial>Ok</button>
|
||||
<button mat-button (click)="onNoClick()">Cancel</button>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-confirm',
|
||||
templateUrl: './confirm.component.html',
|
||||
styleUrls: ['./confirm.component.css']
|
||||
})
|
||||
export class ConfirmDialogComponent {
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<void>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
}
|
||||
|
||||
onNoClick() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
/* icon that can be used to drag a dialog */
|
||||
::ng-deep.dialogdrag-handle {
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
color: #ccc;
|
||||
cursor: move;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
/* make dialog for command response using the display field scrollable */
|
||||
::ng-deep.cmdRespDialog {
|
||||
resize: both;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
/* make only the dialog for command response using the display field movable */
|
||||
/* (hide the close button and the drag icon) */
|
||||
::ng-deep.varRespDialog #dialogclose {
|
||||
display:none ;
|
||||
}
|
||||
|
||||
::ng-deep.varRespDialog #dialogdrag {
|
||||
display:none;
|
||||
}
|
||||
::ng-deep.errRespDialog #dialogclose {
|
||||
display:none ;
|
||||
}
|
||||
|
||||
::ng-deep.errRespDialog #dialogdrag {
|
||||
display:none;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<div id="dialogdrag" cdkDrag cdkDragRootElement=".cdk-overlay-pane">
|
||||
<div class="dialogdrag-handle" cdkDragHandle>
|
||||
<svg width="24px" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z">
|
||||
</path>
|
||||
<path d="M0 0h24v24H0z" fill="none"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<h3> {{ data.title }}</h3>
|
||||
<pre [innerHTML]="data.body"></pre>
|
||||
<mat-dialog-actions fxLayoutAlign="end">
|
||||
<button id="dialogclose" mat-button mat-dialog-close>Close</button>
|
||||
<button id="dialogupdate" mat-button (click)="onUpdate(data.control)"
|
||||
*ngIf="data.updatable">{{data.control.updbtnname}}</button>
|
||||
</mat-dialog-actions>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Component, ViewChild, ElementRef, Inject, OnInit } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { DialogService } from 'src/app/services/dialog.service';
|
||||
import { CmdCtrl } from 'src/app/controls/cmd.control';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dialog',
|
||||
templateUrl: './dialog.component.html',
|
||||
styleUrls: ['./dialog.component.css'],
|
||||
})
|
||||
export class DialogComponent {
|
||||
|
||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
|
||||
}
|
||||
onUpdate(control: CmdCtrl) {
|
||||
if ( control.updbtnname==="Stop update" ){
|
||||
control.stopUpdate();
|
||||
} else {
|
||||
control.startUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<div id="logDisplay">
|
||||
<ul>
|
||||
<li *ngFor="let msg of messages">{{JSON.stringify(msg)}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoggerComponent } from './logger.component';
|
||||
|
||||
describe('LoggerComponent', () => {
|
||||
let component: LoggerComponent;
|
||||
let fixture: ComponentFixture<LoggerComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ LoggerComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(LoggerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Message, WebSocketService } from 'src/app/services/websocket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-logger',
|
||||
templateUrl: './logger.component.html',
|
||||
styleUrls: ['./logger.component.css']
|
||||
})
|
||||
export class LoggerComponent implements OnInit {
|
||||
|
||||
JSON = JSON
|
||||
|
||||
// websocket service object and related subscription for message reception
|
||||
wsSubscription?: Subscription;
|
||||
|
||||
messages: Message[] = [];
|
||||
|
||||
constructor(
|
||||
private wsService: WebSocketService
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.wsSubscription = this.wsService.subject$.subscribe(
|
||||
(msg: Message) => this.messages.push(msg)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<h3>{{ data.title }}</h3>
|
||||
<div mat-dialog-content >
|
||||
<mat-form-field appearance="fill">
|
||||
<label for="answer">{{data.control.question?.display}}</label>
|
||||
<input id="answer" type="text" style="width:10vw" [formControl]="data.control.answerFC">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayoutGap=" 10px" mat-dialog-actions fxLayout="row" fxLayoutAlign="center start">
|
||||
<button mat-button [mat-dialog-close]="true" cdkFocusInitial>Ok</button>
|
||||
<button mat-button [mat-dialog-close]="false">Cancel</button>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { CmdCtrl } from 'src/app/controls/cmd.control';
|
||||
export interface QuestionDialogData {
|
||||
title: string;
|
||||
control: CmdCtrl;
|
||||
}
|
||||
@Component({
|
||||
selector: 'app-question',
|
||||
templateUrl: './question.component.html',
|
||||
styleUrls: ['./question.component.css']
|
||||
})
|
||||
export class QuestionDialogComponent {
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<QuestionDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: QuestionDialogData,
|
||||
) { }
|
||||
onNoClick() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
mat-form-field {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.status {
|
||||
color: green;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.ng-invalid .status {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.dashboard-card {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
}
|
||||
|
||||
.more-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.dashboard-card-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.scope-slider {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.mat-mini-fab.mat-started {
|
||||
background-color: #00a825;
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
<div class="grid-container">
|
||||
<mat-grid-list cols="11" rowHeight="100px">
|
||||
|
||||
<!-- top fullwidth area for scope status display -->
|
||||
<mat-grid-tile [colspan]="11" [rowspan]="1">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ scopetitle }} {{ scopesubtitle }}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
|
||||
<div FxLayoutAlign="row">
|
||||
<label>{{ scopetime }} {{ scopestatus }} </label>
|
||||
</div>
|
||||
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
<!-- left full heigth, narrow width area, for global scope controls -->
|
||||
<mat-grid-tile [colspan]="1" [rowspan]="8">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Scope control</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<button mat-mini-fab color={{startstop_color}} (click)="startorstop()">{{startstop}}</button>
|
||||
<br><br>
|
||||
<div class="scope-slider-div">
|
||||
<label id="scope-slider-refrate-labelid" class="scope-slider-label">refresh rate</label>
|
||||
<label class="scope-slider-value-label"> {{rfrate}} </label>
|
||||
</div>
|
||||
<mat-slider class="scope-slider" min=".1" max="10" step="0.1" [value]="rfrate"
|
||||
aria-labelledby="scope-slider-refrate-labelid" vertical="true" thumbLabel="true"
|
||||
[(ngModel)]="rfrate" (change)="OnRefrateChange()" >
|
||||
</mat-slider>
|
||||
<br><br>
|
||||
<mat-list-item class="sigselect" role="listitem">
|
||||
<mat-form-field class="select-form">
|
||||
<mat-select placeholder="sig select" name="SigSelect" class="SigSelect" [value]="selected_sig.target_id" (selectionChange)="SigChanged($event.value)" >
|
||||
<mat-option *ngFor="let targetid of sig_list" [value]="targetid.target_id" >
|
||||
{{targetid.target_id}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</mat-list-item>
|
||||
<br><br>
|
||||
<mat-slide-toggle [checked]="data_ACK" (change)="onDataACKchange()" [(ngModel)]="data_ACK">data ack
|
||||
</mat-slide-toggle>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
<!-- area for watter fall data display -->
|
||||
<mat-grid-tile [colspan]="7" [rowspan]="3">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div fxLayout="column">
|
||||
<!-- area for the chart -->
|
||||
<div fxFlex="1 1 90% " style="width:100%">
|
||||
<canvas baseChart id="wf"
|
||||
[datasets]="WFDatasets"
|
||||
[options]="WFOptions"
|
||||
[type]="'scatter'">
|
||||
</canvas>
|
||||
</div>
|
||||
<br><br>
|
||||
<!-- area for the control used to select WF data -->
|
||||
<div fxFlex="0 1 10%" style="width:60%">
|
||||
<mat-list-item class="WFselect" role="listitem">
|
||||
<mat-form-field class="select-form">
|
||||
<mat-select placeholder="select data" name="WFSelect" class="WFSelect" [value]="selected_WF" (selectionChange)="WFChanged($event.value)" >
|
||||
<mat-option *ngFor="let graph of WFgraph_list" [value]="graph.title" >
|
||||
{{graph.title}}
|
||||
</mat-option>
|
||||
<mat-option>none</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</mat-list-item>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
<!-- right area for -->
|
||||
<mat-grid-tile [colspan]="3" [rowspan]="2">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
<!-- area for LLR data display -->
|
||||
<mat-grid-tile [colspan]="5" [rowspan]="4">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div fxLayout="column">
|
||||
<div fxFlex="1 1 90% ">
|
||||
<canvas baseChart id="llr" width="90%"
|
||||
[datasets]=" LLRDatasets"
|
||||
[options]="LLROptions"
|
||||
[type]="'scatter'">
|
||||
</canvas>
|
||||
</div>
|
||||
<div fxFlex="0 1 5%" style="width:100%">
|
||||
<div class="form-group" fxFlex="50%"> <mat-list-item class="llrchannelselect" role="listitem">
|
||||
<mat-form-field class="select-form">
|
||||
<mat-select placeholder="Channels(llr view)" name="llrChannelsSelect" class="ChannelsSelect" multiple [value]="selected_llrchannels" (selectionChange)="llrchannelsChanged($event.value)" >
|
||||
<mat-option *ngFor="let graph of llrgraph_list" [value]="graph.title" >
|
||||
{{graph.title}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</mat-list-item> </div>
|
||||
<div class="form-group" fxFlex="50%">
|
||||
<div class="scope-slider-div">
|
||||
<label id="scope-slider-ythresh-labelid" class="scope-slider-label">y threshold </label>
|
||||
<label class="scope-slider-value-label"> {{llrythresh}} </label>
|
||||
</div>
|
||||
<mat-slider class="scope-slider" min="0" max="100" step="1" [value]="llrythresh"
|
||||
aria-labelledby="scope-slider-ythresh-labelid" thumbLabel="true"
|
||||
[(ngModel)]="llrythresh" (change)="OnYthreshChange()" >
|
||||
</mat-slider>
|
||||
</div>
|
||||
</div>
|
||||
<div fxFlex="0 1 5%">
|
||||
<div class="form-group" fxFlex="25%">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>xmin</mat-label>
|
||||
<input matInput type="number" (change)="OnLLRxminChange()" [value]="llrxmin" [(ngModel)]="llrxmin" min="llrmin" [max]="llrmax">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="form-group" fxFlex="25%">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>xmax</mat-label>
|
||||
<input matInput type="number" (change)="OnLLRxmaxChange()" [value]="llrxmax" [(ngModel)]="llrxmax" min="llrmin" [max]="llrmax">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile> <!-- end of LLR area -->
|
||||
|
||||
<!-- area for iq constellation data display -->
|
||||
<mat-grid-tile [colspan]="5" [rowspan]="6">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-content>
|
||||
<div fxLayout="column">
|
||||
<!-- area for the chart -->
|
||||
<div fxFlex="1 1 80% " style="width:60%">
|
||||
<canvas baseChart id="iqc"
|
||||
[datasets]="IQDatasets"
|
||||
[options]="IQOptions"
|
||||
[type]="'scatter'">
|
||||
</canvas>
|
||||
</div>
|
||||
<br><br>
|
||||
<!-- area for the control used to select channel's -->
|
||||
<div fxFlex="0 1 10%" style="width:60%">
|
||||
<mat-list-item class="channelselect" role="listitem">
|
||||
<mat-form-field class="select-form">
|
||||
<mat-select placeholder="Channels(IQ view)" name="ChannelsSelect" class="ChannelsSelect" multiple [value]="selected_channels" (selectionChange)="channelsChanged($event.value)" >
|
||||
<mat-option *ngFor="let graph of iqgraph_list" [value]="graph.title" >
|
||||
{{graph.title}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</mat-list-item>
|
||||
</div>
|
||||
<!-- area for the 4 controls used to select x and y limits for data -->
|
||||
<div fxFlex="0 1 5%">
|
||||
<div class="form-group" fxFlex="25%">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>xmin</mat-label>
|
||||
<input matInput type="number" (change)="OnIQxminChange()" [value]="iqxmin" [(ngModel)]="iqxmin" min="iqmin" [max]="iqmax">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="form-group" fxFlex="25%">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>xmax</mat-label>
|
||||
<input matInput type="number" (change)="OnIQxmaxChange()" [value]="iqxmax" [(ngModel)]="iqxmax" min="iqmin" [max]="iqmax">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="form-group" fxFlex="25%">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>ymin</mat-label>
|
||||
<input matInput type="number" (change)="OnIQyminChange()" [value]="iqymin" [(ngModel)]="iqymin" min="iqmin" [max]="iqmax">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="form-group" fxFlex="25%">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>ymax</mat-label>
|
||||
<input matInput type="number" (change)="OnIQymaxChange()" [value]="iqymax" [(ngModel)]="iqymax" min="iqmin" [max]="iqmax">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile> <!-- end of iq area -->
|
||||
|
||||
</mat-grid-list>
|
||||
</div>
|
||||
@@ -0,0 +1,584 @@
|
||||
import { Component, EventEmitter, OnDestroy, OnInit, Output, QueryList, ViewChildren } from "@angular/core";
|
||||
import { Chart, ChartConfiguration } from 'chart.js';
|
||||
import { BaseChartDirective } from 'ng2-charts';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { IGraphDesc, IScopeDesc, IScopeGraphType, ISigDesc, ScopeApi } from 'src/app/api/scope.api';
|
||||
import { arraybuf_data_offset, Message, WebSocketService, webSockSrc } from "src/app/services/websocket.service";
|
||||
|
||||
export interface RxScopeMessage {
|
||||
msgtype: number;
|
||||
chartid: number;
|
||||
dataid: number;
|
||||
segnum: number;
|
||||
update: boolean;
|
||||
content: ArrayBuffer;
|
||||
}
|
||||
|
||||
const deserialize = (fullbuff: ArrayBuffer): RxScopeMessage => {
|
||||
const header = new DataView(fullbuff, 0, arraybuf_data_offset);
|
||||
return {
|
||||
// source: src.getUint8(0), //header
|
||||
msgtype: header.getUint8(1), //header
|
||||
chartid: header.getUint8(3), //header
|
||||
dataid: header.getUint8(4), //header
|
||||
segnum: header.getUint8(2), //header
|
||||
update: (header.getUint8(5) == 1) ? true : false, //header
|
||||
content: fullbuff.slice(arraybuf_data_offset) // data
|
||||
};
|
||||
}
|
||||
|
||||
const serialize = (msg: TxScopeMessage): ArrayBuffer => {
|
||||
|
||||
const byteArray = new TextEncoder().encode(msg.content);
|
||||
|
||||
let arr = new Uint8Array(byteArray.byteLength + arraybuf_data_offset);
|
||||
arr.set(byteArray, arraybuf_data_offset) //data
|
||||
let buffview = new DataView(arr.buffer);
|
||||
buffview.setUint8(1, msg.msgtype); //header
|
||||
|
||||
return buffview.buffer;
|
||||
}
|
||||
|
||||
export interface TxScopeMessage {
|
||||
msgtype: number;
|
||||
content: string;
|
||||
}
|
||||
|
||||
/*------------------------------------*/
|
||||
/* constants that must match backend (websrv.h or phy_scope.h) */
|
||||
const SCOPEMSG_TYPE_STATUSUPD = 1;
|
||||
const SCOPEMSG_TYPE_REFRATE = 2;
|
||||
const SCOPEMSG_TYPE_TIME = 3;
|
||||
const SCOPEMSG_TYPE_DATA = 10;
|
||||
const SCOPEMSG_TYPE_DATAACK = 11;
|
||||
|
||||
|
||||
const SCOPEMSG_DATA_IQ = 1;
|
||||
const SCOPEMSG_DATA_LLR = 2;
|
||||
const SCOPEMSG_DATA_WF = 3;
|
||||
/*---------------------------------------*/
|
||||
@Component({
|
||||
selector: 'app-scope',
|
||||
templateUrl: './scope.component.html',
|
||||
styleUrls: ['./scope.component.css'],
|
||||
})
|
||||
|
||||
export class ScopeComponent implements OnInit, OnDestroy {
|
||||
//data for scope status area
|
||||
scopetitle = '';
|
||||
scopesubtitle = '';
|
||||
scopetime = '';
|
||||
scopestatus = 'stopped';
|
||||
//data for scope control area
|
||||
startstop = 'start';
|
||||
startstop_color = 'warn';
|
||||
rfrate = 2;
|
||||
data_ACK = false;
|
||||
//data for scope iq constellation area
|
||||
iqgraph_list: IGraphDesc[] = [];
|
||||
selected_channels = [""];
|
||||
iqmax = 32767;
|
||||
iqmin = -32767;
|
||||
iqxmin = this.iqmin;
|
||||
iqymin = this.iqmin;
|
||||
iqxmax = this.iqmax;
|
||||
iqymax = this.iqmax;
|
||||
//data for scope LLR area
|
||||
llrgraph_list: IGraphDesc[] = [];
|
||||
selected_llrchannels = [""];
|
||||
sig_list: ISigDesc[] = [{ target_id: 0, antenna_id: 0 },
|
||||
{ target_id: 1, antenna_id: 0 },
|
||||
{ target_id: 2, antenna_id: 0 },
|
||||
{ target_id: 3, antenna_id: 0 },
|
||||
];
|
||||
selected_sig: ISigDesc = { target_id: 0, antenna_id: 0 };
|
||||
llrythresh = 5;
|
||||
llrmin = 0;
|
||||
llrmax = 200000;
|
||||
llrxmin = this.llrmin;
|
||||
llrxmax = this.llrmax;
|
||||
//data for scope WatterFall area
|
||||
WFgraph_list: IGraphDesc[] = [];
|
||||
selected_WF = "";
|
||||
llrchart?: Chart;
|
||||
iqcchart?: Chart;
|
||||
wfchart?: Chart;
|
||||
nwf: number[] = [0, 0, 0, 0];
|
||||
|
||||
// websocket service object and related subscription for message reception
|
||||
wsSubscription?: Subscription;
|
||||
|
||||
@Output() ScopeEnabled = new EventEmitter<boolean>();
|
||||
|
||||
@ViewChildren(BaseChartDirective) charts?: QueryList<BaseChartDirective>;
|
||||
|
||||
public IQDatasets: ChartConfiguration<'scatter'>['data']['datasets'] = [
|
||||
{
|
||||
data: [],
|
||||
label: 'C1',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
fill: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'yellow',
|
||||
backgroundColor: 'yellow',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'yellow',
|
||||
// parsing: false,
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: 'C2',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'cyan',
|
||||
backgroundColor: 'cyan',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'cyan',
|
||||
// parsing: false,
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: 'C3',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'red',
|
||||
backgroundColor: 'red',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'red',
|
||||
// parsing: false,
|
||||
}
|
||||
];
|
||||
|
||||
public LLRDatasets: ChartConfiguration<'scatter'>['data']['datasets'] = [
|
||||
{
|
||||
data: [],
|
||||
label: 'LLR1',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
fill: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'yellow',
|
||||
backgroundColor: 'yellow',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'yellow',
|
||||
// parsing: false,
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: 'LL2',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'cyan',
|
||||
backgroundColor: 'cyan',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'cyan',
|
||||
parsing: false,
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: 'LLR3',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'red',
|
||||
backgroundColor: 'red',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'red',
|
||||
parsing: false,
|
||||
}
|
||||
];
|
||||
|
||||
public WFDatasets: ChartConfiguration<'scatter'>['data']['datasets'] = [
|
||||
{
|
||||
data: [],
|
||||
label: 'WFblue',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
fill: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'blue',
|
||||
backgroundColor: 'blue',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'blue',
|
||||
// parsing: false,
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: 'WFgreen',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'green',
|
||||
backgroundColor: 'green',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'green',
|
||||
// parsing: false,
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: 'WFyellow',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'yellow',
|
||||
backgroundColor: 'yellow',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'yellow',
|
||||
// parsing: false,
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
label: 'WFred',
|
||||
pointRadius: 0.5,
|
||||
showLine: false,
|
||||
animation: false,
|
||||
pointStyle: 'circle',
|
||||
pointBackgroundColor: 'red',
|
||||
backgroundColor: 'red',
|
||||
borderWidth: 0,
|
||||
pointBorderColor: 'red',
|
||||
// parsing: false,
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
|
||||
public IQOptions: ChartConfiguration<'scatter'>['options'] = {
|
||||
responsive: true,
|
||||
aspectRatio: 1,
|
||||
// scales: {
|
||||
// xAxes: {
|
||||
// min: -5,
|
||||
// max:5,
|
||||
// }
|
||||
// },
|
||||
plugins: { legend: { display: true, labels: { boxWidth: 10, boxHeight: 10 } }, tooltip: { enabled: false, }, },
|
||||
};
|
||||
|
||||
public LLROptions: ChartConfiguration<'scatter'>['options'] = {
|
||||
responsive: true,
|
||||
aspectRatio: 3,
|
||||
scales: {
|
||||
xAxes: {
|
||||
min: 0,
|
||||
},
|
||||
// yAxes: {
|
||||
// min: -100,
|
||||
// max: 100
|
||||
// }
|
||||
},
|
||||
plugins: { legend: { display: true, labels: { boxWidth: 10, boxHeight: 10 } }, tooltip: { enabled: false, }, },
|
||||
};
|
||||
|
||||
public WFOptions: ChartConfiguration<'scatter'>['options'] = {
|
||||
responsive: true,
|
||||
aspectRatio: 5,
|
||||
scales: {
|
||||
xAxes: {
|
||||
min: 0,
|
||||
// max:800,
|
||||
},
|
||||
yAxes: {
|
||||
min: 0,
|
||||
max: 80,
|
||||
reverse: true,
|
||||
}
|
||||
},
|
||||
plugins: { legend: { display: true, labels: { boxWidth: 10, boxHeight: 10 } }, tooltip: { enabled: false, }, },
|
||||
}
|
||||
|
||||
|
||||
constructor(
|
||||
private scopeApi: ScopeApi,
|
||||
private wsService: WebSocketService
|
||||
) {
|
||||
console.log("Scope constructor ");
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
console.log("Scope ngOnInit ");
|
||||
this.scopeApi.getScopeInfos$().subscribe(resp => {
|
||||
this.configScope(resp);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
console.log("Scope ngOnDestroy ");
|
||||
this.wsSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
DecodScopeBinmsgToString(message: ArrayBuffer) {
|
||||
const enc = new TextDecoder("utf-8");
|
||||
return enc.decode(message);
|
||||
}
|
||||
|
||||
private configScope(resp: IScopeDesc) {
|
||||
if (resp.title === "none") {
|
||||
this.ScopeEnabled.emit(false);
|
||||
} else {
|
||||
this.ScopeEnabled.emit(true);
|
||||
this.scopetitle = resp.title;
|
||||
this.iqgraph_list.length = 0;
|
||||
this.llrgraph_list.length = 0;
|
||||
for (let graphIndex = 0; graphIndex < resp.graphs.length; graphIndex++) {
|
||||
if (resp.graphs[graphIndex].type == IScopeGraphType.IQs) {
|
||||
this.iqgraph_list.push(resp.graphs[graphIndex]);
|
||||
this.IQDatasets[this.iqgraph_list.length - 1].label = resp.graphs[graphIndex].title;
|
||||
}
|
||||
if (resp.graphs[graphIndex].type == IScopeGraphType.LLR) {
|
||||
this.llrgraph_list.push(resp.graphs[graphIndex]);
|
||||
this.LLRDatasets[this.llrgraph_list.length - 1].label = resp.graphs[graphIndex].title;
|
||||
}
|
||||
if (resp.graphs[graphIndex].type == IScopeGraphType.WF) {
|
||||
this.WFgraph_list.push(resp.graphs[graphIndex]);
|
||||
}
|
||||
}
|
||||
this.charts?.forEach((child) => {
|
||||
child.chart?.update()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private ProcessScopeMsg(message: RxScopeMessage) {
|
||||
if (this.scopestatus === "starting") {
|
||||
this.scopestatus = 'started';
|
||||
this.startstop = 'stop';
|
||||
this.startstop_color = 'started';
|
||||
}
|
||||
let d = 0;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
switch (message.msgtype) {
|
||||
case SCOPEMSG_TYPE_TIME:
|
||||
this.scopetime = this.DecodScopeBinmsgToString(message.content);
|
||||
break;
|
||||
case SCOPEMSG_TYPE_DATA:
|
||||
const bufferview = new DataView(message.content);
|
||||
|
||||
|
||||
switch (message.chartid) {
|
||||
case SCOPEMSG_DATA_IQ:
|
||||
this.IQDatasets[message.dataid].data.length = 0;
|
||||
if (message.update) {
|
||||
console.log("Starting scope update chart " + message.chartid.toString() + ", dataset " + message.dataid.toString());
|
||||
}
|
||||
for (let i = 0; i < bufferview.byteLength; i = i + 4) {
|
||||
this.IQDatasets[message.dataid].data[i / 4] = { x: bufferview.getInt16(i, true), y: bufferview.getInt16(i + 2, true) };
|
||||
}
|
||||
|
||||
if (message.update) {
|
||||
this.iqcchart!.update();
|
||||
}
|
||||
break;
|
||||
case SCOPEMSG_DATA_LLR:
|
||||
if (message.update) {
|
||||
console.log("Starting scope update chart " + message.chartid.toString() + ", dataset " + message.dataid.toString());
|
||||
}
|
||||
this.LLRDatasets[message.dataid].data.length = 0;
|
||||
let xoffset = 0;
|
||||
d = 0;
|
||||
for (let i = 4; i < (bufferview.byteLength - 2); i = i + 4) {
|
||||
xoffset = xoffset + bufferview.getInt16(i + 2, true);
|
||||
this.LLRDatasets[message.dataid].data[d] = { x: xoffset, y: bufferview.getInt16(i, true) };
|
||||
d++;
|
||||
}
|
||||
this.LLRDatasets[message.dataid].data[d] = { x: bufferview.getInt32(0, true), y: 0 };
|
||||
if (message.update) {
|
||||
this.llrchart!.update();
|
||||
}
|
||||
|
||||
break;
|
||||
case SCOPEMSG_DATA_WF:
|
||||
if (message.update) {
|
||||
console.log("Starting scope update chart " + message.chartid.toString() + ", dataset " + message.dataid.toString());
|
||||
if (message.segnum == 0) {
|
||||
for (let i = 0; i < this.WFDatasets.length; i++) {
|
||||
this.nwf[i] = 0;
|
||||
this.WFDatasets[i].data.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 2; i < bufferview.byteLength - 2; i = i + 4) {// first 16 bits in buffer contains the number of points in the message
|
||||
x = bufferview.getInt16(i, true);
|
||||
y = bufferview.getInt16(i + 2, true);
|
||||
this.wfchart!.scales.xAxes.max = bufferview.getInt16(bufferview.byteLength - 4, true);
|
||||
this.WFDatasets[message.dataid].data[this.nwf[message.dataid]] = { x: x, y: y };
|
||||
this.nwf[message.dataid]++;
|
||||
}
|
||||
if (message.update) {
|
||||
this.wfchart!.update();
|
||||
console.log(" scope update completed " + d.toString() + "points, ");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.sendMsg(SCOPEMSG_TYPE_DATAACK, "Chart " + message.chartid.toString() + ", dataset " + message.dataid.toString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private sendMsg(type: number, strmessage: string) {
|
||||
this.wsService.send({
|
||||
source: webSockSrc.softscope,
|
||||
fullbuff: serialize({
|
||||
msgtype: type,
|
||||
content: strmessage
|
||||
})
|
||||
});
|
||||
console.log("Scope sent msg type " + type.toString() + " " + strmessage);
|
||||
}
|
||||
|
||||
private SendScopeParams(name: string, value: string, graphid: number) {
|
||||
this.scopeApi.setScopeParams$({ name: name, value: value, graphid: graphid }).subscribe();
|
||||
}
|
||||
|
||||
startorstop() {
|
||||
if (this.scopestatus === 'stopped') {
|
||||
|
||||
this.scopeApi.setScopeParams$({ name: "startstop", value: "start" }).subscribe(
|
||||
() => {
|
||||
this.llrchart = Chart.getChart("llr");
|
||||
this.iqcchart = Chart.getChart("iqc");
|
||||
this.wfchart = Chart.getChart("wf");
|
||||
this.IQDatasets.forEach((dataset) => { dataset.data.length = 0 });
|
||||
this.LLRDatasets.forEach((dataset) => { dataset.data.length = 0 });
|
||||
this.charts?.forEach((child, index) => { child.chart?.update() });
|
||||
this.scopestatus = 'starting';
|
||||
this.SigChanged(this.selected_sig.target_id);
|
||||
this.OnRefrateChange();
|
||||
this.OnIQxminChange();
|
||||
this.OnIQxmaxChange();
|
||||
this.OnIQyminChange();
|
||||
this.OnIQymaxChange();
|
||||
this.OnYthreshChange();
|
||||
this.OnLLRxminChange();
|
||||
this.OnLLRxmaxChange();
|
||||
this.channelsChanged(this.selected_channels);
|
||||
this.llrchannelsChanged(this.selected_llrchannels);
|
||||
this.WFChanged(this.selected_WF);
|
||||
for (let i = 0; i < this.WFDatasets.length; i++) {
|
||||
this.nwf[i] = 0;
|
||||
this.WFDatasets[i].data.length = 0;
|
||||
}
|
||||
|
||||
this.wsSubscription = this.wsService.subject$.subscribe(
|
||||
(msg: Message) => this.ProcessScopeMsg(deserialize(msg.fullbuff))
|
||||
)
|
||||
},
|
||||
err => {
|
||||
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.scopeApi.setScopeParams$({ name: "startstop", value: "stop" }).subscribe(
|
||||
() => {
|
||||
if (this.wsSubscription)
|
||||
this.wsSubscription.unsubscribe();
|
||||
|
||||
this.scopestatus = 'stopped';
|
||||
this.startstop = 'start';
|
||||
this.startstop_color = 'warn';
|
||||
this.charts?.forEach((child, index) => { child.chart?.update() });
|
||||
|
||||
},
|
||||
err => {
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
OnRefrateChange() {
|
||||
this.SendScopeParams("refrate", (this.rfrate * 10).toString(), 0);
|
||||
}
|
||||
|
||||
OnLLRxminChange() {
|
||||
this.SendScopeParams("llrxmin", (this.llrxmin).toString(), 0);
|
||||
}
|
||||
OnLLRxmaxChange() {
|
||||
this.SendScopeParams("llrxmax", (this.llrxmax).toString(), 0);
|
||||
}
|
||||
|
||||
OnIQxminChange() {
|
||||
this.SendScopeParams("xmin", (this.iqxmin).toString(), 0);
|
||||
}
|
||||
OnIQxmaxChange() {
|
||||
this.SendScopeParams("xmax", (this.iqxmax).toString(), 0);
|
||||
}
|
||||
OnIQyminChange() {
|
||||
this.SendScopeParams("ymin", (this.iqymin).toString(), 0);
|
||||
}
|
||||
OnIQymaxChange() {
|
||||
this.SendScopeParams("ymax", (this.iqymax).toString(), 0);
|
||||
}
|
||||
|
||||
|
||||
channelsChanged(titles: string[]) {
|
||||
this.selected_channels = titles;
|
||||
this.iqgraph_list.forEach(graph => {
|
||||
const [enabled] = titles.filter(value => graph.title === value)
|
||||
this.SendScopeParams("enabled", enabled ? "true" : "false", graph.srvidx);
|
||||
})
|
||||
}
|
||||
|
||||
llrchannelsChanged(titles: string[]) {
|
||||
this.selected_llrchannels = titles;
|
||||
this.llrgraph_list.forEach(graph => {
|
||||
const [enabled] = titles.filter(value => graph.title === value)
|
||||
this.SendScopeParams("enabled", enabled ? "true" : "false", graph.srvidx);
|
||||
})
|
||||
}
|
||||
|
||||
SigChanged(value: number) {
|
||||
this.selected_sig.target_id = value;
|
||||
if (this.scopetitle === "gNB")
|
||||
this.scopesubtitle = " - sig from UE" + value.toString() + " antenna" + this.selected_sig.antenna_id;
|
||||
else
|
||||
this.scopesubtitle = " - sig from gNB" + value.toString() + " antenna" + this.selected_sig.antenna_id;;
|
||||
this.SendScopeParams("TargetSelect", value.toString(), 0);
|
||||
}
|
||||
|
||||
WFChanged(value: string) {
|
||||
this.selected_WF = value;
|
||||
|
||||
for (let i = 0; i < this.WFgraph_list.length; i++) {
|
||||
if (this.WFgraph_list[i].title === value) {
|
||||
this.SendScopeParams("enabled", "true", this.WFgraph_list[i].srvidx);
|
||||
this.WFDatasets[0].label = value;
|
||||
this.WFDatasets[1].label = "(>avg*2)";
|
||||
this.WFDatasets[2].label = "(>avg*10)";
|
||||
this.WFDatasets[3].label = "(>avg*100)";
|
||||
} else {
|
||||
this.SendScopeParams("enabled", "false", this.WFgraph_list[i].srvidx);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < this.WFDatasets.length; i++) {
|
||||
this.nwf[i] = 0;
|
||||
this.WFDatasets[i].data.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
onDataACKchange() {
|
||||
this.SendScopeParams("DataAck", this.data_ACK.toString(), 0);
|
||||
}
|
||||
|
||||
OnYthreshChange() {
|
||||
this.SendScopeParams("llrythresh", this.llrythresh.toString(), 0);
|
||||
}
|
||||
}
|
||||
95
common/utils/websrv/frontend/src/app/controls/cmd.control.ts
Normal file
95
common/utils/websrv/frontend/src/app/controls/cmd.control.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { UntypedFormArray, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { ICommand, ICommandOptions, IQuestion } from 'src/app/api/commands.api';
|
||||
|
||||
const enum CmdFCN {
|
||||
name = 'name',
|
||||
vars = 'variables',
|
||||
confirm = 'confirm',
|
||||
answer = "answer"
|
||||
}
|
||||
|
||||
export class CmdCtrl extends UntypedFormGroup {
|
||||
|
||||
confirm?: string
|
||||
question?: IQuestion
|
||||
cmdname: string
|
||||
options?: ICommandOptions[]
|
||||
public ResUpdTimer?: Observable<number>
|
||||
public ResUpdTimerSubscriber?: Subscription
|
||||
updbtnname: string
|
||||
constructor(cmd: ICommand) {
|
||||
super({});
|
||||
|
||||
this.addControl(CmdFCN.name, new UntypedFormControl(cmd.name));
|
||||
this.addControl(CmdFCN.answer, new UntypedFormControl(""));
|
||||
this.addControl(CmdFCN.vars, new UntypedFormArray([]));
|
||||
|
||||
|
||||
this.confirm = cmd.confirm;
|
||||
this.question = cmd.question;
|
||||
this.cmdname = cmd.name;
|
||||
this.options = cmd.options;
|
||||
this.updbtnname = "Start update"
|
||||
}
|
||||
|
||||
api() {
|
||||
const doc: ICommand = {
|
||||
name: this.nameFC.value,
|
||||
param: this.question
|
||||
? { name: this.question!.pname, value: this.answerFC.value, type: this.question!.type, modifiable: false }
|
||||
: undefined,
|
||||
options: this.options
|
||||
};
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
isResUpdatable(): boolean {
|
||||
if (this.options) {
|
||||
for (let opt = 0; opt < this.options.length; opt++) {
|
||||
if (this.options[opt] == ICommandOptions.update)
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
stopUpdate() {
|
||||
if (this.ResUpdTimerSubscriber) {
|
||||
this.ResUpdTimerSubscriber.unsubscribe();
|
||||
this.updbtnname = "Start update"
|
||||
}
|
||||
}
|
||||
|
||||
startUpdate() {
|
||||
if (this.ResUpdTimerSubscriber && this.ResUpdTimer) {
|
||||
this.ResUpdTimerSubscriber = this.ResUpdTimer.subscribe();
|
||||
this.updbtnname = "Stop update"
|
||||
}
|
||||
}
|
||||
|
||||
get nameFC() {
|
||||
return this.get(CmdFCN.name) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set nameFC(fc: UntypedFormControl) {
|
||||
this.setControl(CmdFCN.name, fc);
|
||||
}
|
||||
|
||||
get answerFC() {
|
||||
return this.get(CmdFCN.answer) as UntypedFormControl;
|
||||
}
|
||||
|
||||
get varsFA() {
|
||||
return this.get(CmdFCN.vars) as UntypedFormArray;
|
||||
}
|
||||
|
||||
set varsFA(fa: UntypedFormArray) {
|
||||
this.setControl(CmdFCN.vars, fa);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { IInfo } from '../api/commands.api';
|
||||
import { IArgType } from '../api/commands.api';
|
||||
|
||||
const enum InfosFCN {
|
||||
name = 'name',
|
||||
value = "value",
|
||||
type = "type",
|
||||
modifiable = "modifiable"
|
||||
}
|
||||
|
||||
|
||||
export class InfoCtrl extends UntypedFormGroup {
|
||||
type: IArgType;
|
||||
constructor(ivar: IInfo) {
|
||||
super({});
|
||||
this.type = ivar.type;
|
||||
this.addControl(InfosFCN.name, new UntypedFormControl(ivar.name));
|
||||
this.addControl(InfosFCN.value, new UntypedFormControl(ivar.value));
|
||||
this.addControl(InfosFCN.type, new UntypedFormControl(ivar.type));
|
||||
this.addControl(InfosFCN.modifiable, new UntypedFormControl(ivar.modifiable));
|
||||
}
|
||||
|
||||
api() {
|
||||
const doc: IInfo = {
|
||||
name: this.nameFC.value,
|
||||
value: String(this.valueFC.value), //FIXME
|
||||
type: this.typeFC.value,
|
||||
modifiable: this.modifiableFC.value
|
||||
};
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
get nameFC() {
|
||||
return this.get(InfosFCN.name) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set nameFC(control: UntypedFormControl) {
|
||||
this.setControl(InfosFCN.name, control);
|
||||
}
|
||||
|
||||
get valueFC() {
|
||||
return this.get(InfosFCN.value) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set valueFC(control: UntypedFormControl) {
|
||||
this.setControl(InfosFCN.value, control);
|
||||
}
|
||||
|
||||
get typeFC() {
|
||||
return this.get(InfosFCN.type) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set typeFC(control: UntypedFormControl) {
|
||||
this.setControl(InfosFCN.type, control);
|
||||
}
|
||||
|
||||
get modifiableFC() {
|
||||
return this.get(InfosFCN.modifiable) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set modifiableFC(control: UntypedFormControl) {
|
||||
this.setControl(InfosFCN.modifiable, control);
|
||||
}
|
||||
|
||||
get btnTxtFC() {
|
||||
if (this.type != IArgType.configfile)
|
||||
return "set"
|
||||
else
|
||||
return "download"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { UntypedFormArray, UntypedFormGroup } from '@angular/forms';
|
||||
import { IModule } from '../api/commands.api';
|
||||
|
||||
const enum ModuleFCN {
|
||||
vars = 'variables',
|
||||
cmds = 'commands'
|
||||
}
|
||||
|
||||
export class ModuleCtrl extends UntypedFormGroup {
|
||||
|
||||
name: string
|
||||
|
||||
constructor(imodule: IModule) {
|
||||
super({})
|
||||
this.name = imodule.name
|
||||
this.addControl(ModuleFCN.vars, new UntypedFormArray([]))
|
||||
this.addControl(ModuleFCN.cmds, new UntypedFormArray([]))
|
||||
}
|
||||
|
||||
get varsFA() {
|
||||
return this.get(ModuleFCN.vars) as UntypedFormArray;
|
||||
}
|
||||
|
||||
set varsFA(fa: UntypedFormArray) {
|
||||
this.setControl(ModuleFCN.vars, fa);
|
||||
}
|
||||
|
||||
get cmdsFA() {
|
||||
return this.get(ModuleFCN.cmds) as UntypedFormArray;
|
||||
}
|
||||
|
||||
set cmdsFA(fa: UntypedFormArray) {
|
||||
this.setControl(ModuleFCN.cmds, fa);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import { UntypedFormControl, UntypedFormGroup } from "@angular/forms";
|
||||
import { IArgType, IColumn, IParam } from "../api/commands.api";
|
||||
|
||||
|
||||
enum ParamFCN {
|
||||
value = 'value',
|
||||
}
|
||||
|
||||
|
||||
export class ParamCtrl extends UntypedFormGroup {
|
||||
|
||||
col: IColumn
|
||||
constructor(public param: IParam) {
|
||||
super({})
|
||||
|
||||
this.col = param.col
|
||||
|
||||
let control: UntypedFormControl
|
||||
switch (param.col.type) {
|
||||
case IArgType.boolean:
|
||||
control = new UntypedFormControl((param.value === 'true') ? true : false);
|
||||
break;
|
||||
|
||||
case IArgType.loglvl:
|
||||
control = new UntypedFormControl(param.value);
|
||||
break;
|
||||
|
||||
default:
|
||||
control = new UntypedFormControl(param.value)
|
||||
}
|
||||
|
||||
if (!param.col.modifiable) control.disable()
|
||||
|
||||
this.addControl(ParamFCN.value, control)
|
||||
}
|
||||
|
||||
get valueFC() {
|
||||
return this.get(ParamFCN.value) as UntypedFormControl
|
||||
}
|
||||
|
||||
set valueFC(fc: UntypedFormControl) {
|
||||
this.setControl(ParamFCN.value, fc);
|
||||
}
|
||||
|
||||
api() {
|
||||
let value: string
|
||||
|
||||
switch (this.col.type) {
|
||||
case IArgType.boolean:
|
||||
value = String(this.valueFC.value);
|
||||
break;
|
||||
|
||||
default:
|
||||
value = this.valueFC.value
|
||||
}
|
||||
|
||||
const doc: IParam = {
|
||||
value: value,
|
||||
col: this.col
|
||||
}
|
||||
|
||||
return doc
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
51
common/utils/websrv/frontend/src/app/controls/row.control.ts
Normal file
51
common/utils/websrv/frontend/src/app/controls/row.control.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
import { UntypedFormArray, FormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { IArgType, IParam, IRow } from '../api/commands.api';
|
||||
import { ParamCtrl } from './param.control';
|
||||
|
||||
|
||||
|
||||
enum RowFCN {
|
||||
paramsFA = 'params',
|
||||
}
|
||||
|
||||
|
||||
export class RowCtrl extends UntypedFormGroup {
|
||||
|
||||
cmdName: string
|
||||
rawIndex: number
|
||||
|
||||
constructor(row: IRow) {
|
||||
super({})
|
||||
|
||||
this.cmdName = row.cmdName
|
||||
this.rawIndex = row.rawIndex
|
||||
this.addControl(RowFCN.paramsFA, new UntypedFormArray(row.params.map(param => new ParamCtrl(param))))
|
||||
}
|
||||
|
||||
get paramsFA() {
|
||||
return this.get(RowFCN.paramsFA) as UntypedFormArray
|
||||
}
|
||||
|
||||
set paramsFA(fa: UntypedFormArray) {
|
||||
this.setControl(RowFCN.paramsFA, fa);
|
||||
}
|
||||
|
||||
get paramsCtrls(): ParamCtrl[] {
|
||||
return this.paramsFA.controls as ParamCtrl[]
|
||||
}
|
||||
|
||||
api() {
|
||||
|
||||
const doc: IRow = {
|
||||
rawIndex: this.rawIndex,
|
||||
cmdName: this.cmdName,
|
||||
params: this.paramsCtrls.map(control => control.api())
|
||||
}
|
||||
|
||||
return doc
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
74
common/utils/websrv/frontend/src/app/controls/var.control.ts
Normal file
74
common/utils/websrv/frontend/src/app/controls/var.control.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { IInfo } from '../api/commands.api';
|
||||
import { IArgType } from '../api/commands.api';
|
||||
|
||||
const enum VariablesFCN {
|
||||
name = 'name',
|
||||
value = "value",
|
||||
type = "type",
|
||||
modifiable = "modifiable"
|
||||
}
|
||||
|
||||
|
||||
export class VarCtrl extends UntypedFormGroup {
|
||||
type: IArgType;
|
||||
constructor(ivar: IInfo) {
|
||||
super({});
|
||||
this.type = ivar.type;
|
||||
this.addControl(VariablesFCN.name, new UntypedFormControl(ivar.name));
|
||||
this.addControl(VariablesFCN.value, new UntypedFormControl(ivar.value));
|
||||
this.addControl(VariablesFCN.type, new UntypedFormControl(ivar.type));
|
||||
this.addControl(VariablesFCN.modifiable, new UntypedFormControl(ivar.modifiable));
|
||||
}
|
||||
|
||||
api() {
|
||||
const doc: IInfo = {
|
||||
name: this.nameFC.value,
|
||||
value: String(this.valueFC.value), //FIXME
|
||||
type: this.typeFC.value,
|
||||
modifiable: this.modifiableFC.value
|
||||
};
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
get nameFC() {
|
||||
return this.get(VariablesFCN.name) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set nameFC(control: UntypedFormControl) {
|
||||
this.setControl(VariablesFCN.name, control);
|
||||
}
|
||||
|
||||
get valueFC() {
|
||||
return this.get(VariablesFCN.value) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set valueFC(control: UntypedFormControl) {
|
||||
this.setControl(VariablesFCN.value, control);
|
||||
}
|
||||
|
||||
get typeFC() {
|
||||
return this.get(VariablesFCN.type) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set typeFC(control: UntypedFormControl) {
|
||||
this.setControl(VariablesFCN.type, control);
|
||||
}
|
||||
|
||||
get modifiableFC() {
|
||||
return this.get(VariablesFCN.modifiable) as UntypedFormControl;
|
||||
}
|
||||
|
||||
set modifiableFC(control: UntypedFormControl) {
|
||||
this.setControl(VariablesFCN.modifiable, control);
|
||||
}
|
||||
|
||||
get btnTxtFC() {
|
||||
if (this.type != IArgType.configfile)
|
||||
return "set"
|
||||
else
|
||||
return "download"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
import { DialogService as DialogService } from '../services/dialog.service';
|
||||
|
||||
@Injectable()
|
||||
export class ErrorInterceptor implements HttpInterceptor {
|
||||
constructor(public dialogService: DialogService) { }
|
||||
|
||||
intercept(request: HttpRequest<unknown>, next: HttpHandler) {
|
||||
return next.handle(request).pipe(
|
||||
// tap((event: HttpEvent<any>) => {
|
||||
// if (event instanceof HttpResponse) {
|
||||
// switch (event.status) {
|
||||
// case 200:
|
||||
// case 201:
|
||||
// this.log(GREEN, request.method + ' ' + event.status + ' Success');
|
||||
// this.dialogService.openSnackBar(request.method + ' ' + event.status + ' Success');
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // return throwError(event.body);
|
||||
// }
|
||||
// }),
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
switch (error.status) {
|
||||
case 400:
|
||||
case 403:
|
||||
case 501:
|
||||
case 500:
|
||||
this.log(YELLOW, request.method + ' ' + error.status + ' Error: ' + error.error);
|
||||
this.dialogService.openErrorDialog(error);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return throwError(error.error);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private log = (color: string, txt: string) => console.log(color, '[API] ' + txt);
|
||||
}
|
||||
|
||||
const RED = '\x1b[31m%s\x1b[0m';
|
||||
const GREEN = '\x1b[32m%s\x1b[0m';
|
||||
const YELLOW = '\x1b[33m%s\x1b[0m';
|
||||
const MAGENTA = '\x1b[35m%s\x1b[0m';
|
||||
const CYAN = '\x1b[36m%s%s\x1b[0m';
|
||||
@@ -0,0 +1,8 @@
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { ErrorInterceptor } from './error.interceptor';
|
||||
import { SpinnerInterceptor } from './spinner.interceptor';
|
||||
|
||||
export const InterceptorProviders = [
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: SpinnerInterceptor, multi: true },
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
|
||||
];
|
||||
@@ -0,0 +1,29 @@
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { LoadingService } from '../services/loading.service';
|
||||
|
||||
@Injectable()
|
||||
export class SpinnerInterceptor implements HttpInterceptor {
|
||||
activeRequests = 0;
|
||||
|
||||
constructor(private loadingService: LoadingService) { }
|
||||
|
||||
intercept(request: HttpRequest<unknown>, next: HttpHandler) {
|
||||
if (this.activeRequests === 0) {
|
||||
this.loadingService.startLoading();
|
||||
}
|
||||
|
||||
this.activeRequests++;
|
||||
|
||||
return next.handle(request).pipe(
|
||||
finalize(() => {
|
||||
this.activeRequests--;
|
||||
if (this.activeRequests === 0) {
|
||||
this.loadingService.stopLoading();
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
160
common/utils/websrv/frontend/src/app/services/dialog.service.ts
Normal file
160
common/utils/websrv/frontend/src/app/services/dialog.service.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Injectable, ViewChild, ElementRef } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Observable } from 'rxjs';
|
||||
import { of } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { IResp, ICommandOptions} from '../api/commands.api';
|
||||
import { ConfirmDialogComponent } from '../components/confirm/confirm.component';
|
||||
import { QuestionDialogComponent } from '../components/question/question.component';
|
||||
import { DialogComponent } from '../components/dialog/dialog.component';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { CmdCtrl } from 'src/app/controls/cmd.control';
|
||||
import { CommandsComponent } from '../components/commands/commands.component';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DialogService {
|
||||
public isDialogOpen = false;
|
||||
cmdDialogRef : any;
|
||||
constructor(
|
||||
private _dialog: MatDialog,
|
||||
private _snackBar: MatSnackBar,
|
||||
) { }
|
||||
|
||||
openErrorDialog(error: HttpErrorResponse): Observable<any> {
|
||||
if (this.isDialogOpen) {
|
||||
return of(undefined);
|
||||
}
|
||||
this.isDialogOpen = true;
|
||||
return this._dialog.open(DialogComponent, {
|
||||
width: '900px',
|
||||
data: {
|
||||
title: error.status + ' Error',
|
||||
body: error.error,
|
||||
},
|
||||
panelClass: 'errRespDialog',
|
||||
})
|
||||
.afterClosed()
|
||||
.pipe(tap(() => this.isDialogOpen = false));
|
||||
|
||||
}
|
||||
|
||||
openCmdDialog(control: CmdCtrl, resp: IResp, title?: string): Observable<IResp> {
|
||||
this.isDialogOpen = true;
|
||||
console.log('Open Cmd dialog');
|
||||
var updatable=false;
|
||||
if (control.options) {
|
||||
for (let opt=0; opt < control.options.length ; opt++) {
|
||||
if (control.options[opt] == ICommandOptions.update)
|
||||
updatable=true;
|
||||
}
|
||||
}
|
||||
this.cmdDialogRef = this._dialog.open(DialogComponent, {
|
||||
height: '80%',
|
||||
hasBackdrop: false,
|
||||
|
||||
data: {
|
||||
control: control,
|
||||
title: title,
|
||||
body: resp.display!.join("</p><p>"),
|
||||
updatable: updatable,
|
||||
},
|
||||
panelClass: 'cmdRespDialog',
|
||||
});
|
||||
|
||||
this.cmdDialogRef.afterClosed().subscribe(( ) => {
|
||||
console.log('The dialog was closed');
|
||||
this.isDialogOpen = false;
|
||||
});
|
||||
|
||||
return of(resp)
|
||||
}
|
||||
|
||||
updateCmdDialog(control: CmdCtrl, resp: IResp, title?: string): Observable<IResp> {
|
||||
if (this.cmdDialogRef && this.isDialogOpen && resp.display.length) {
|
||||
this.cmdDialogRef.componentInstance.data = {
|
||||
control: control,
|
||||
title: title,
|
||||
body: resp.display!.join("</p><p>"),
|
||||
updatable: true};
|
||||
return of(resp);
|
||||
} else {
|
||||
return this.openCmdDialog(control, resp, title);
|
||||
}
|
||||
}
|
||||
|
||||
openVarRespDialog(resp: IResp): Observable<IResp> {
|
||||
if (this.isDialogOpen || !resp.display.length) {
|
||||
return of(resp);
|
||||
}
|
||||
console.log('Open Var dialog');
|
||||
this.isDialogOpen = true;
|
||||
const dialogRef = this._dialog.open(DialogComponent, {
|
||||
width: '900px',
|
||||
hasBackdrop: true,
|
||||
data: {
|
||||
title: resp.display![0],
|
||||
},
|
||||
panelClass: 'varRespDialog',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
console.log('The dialog was closed');
|
||||
this.isDialogOpen = false;
|
||||
});
|
||||
|
||||
return of(resp)
|
||||
}
|
||||
|
||||
openSnackBar(title: string): void {
|
||||
this._snackBar.open(title, undefined, {
|
||||
duration: 500,
|
||||
horizontalPosition: 'center',
|
||||
verticalPosition: 'bottom',
|
||||
});
|
||||
}
|
||||
|
||||
openConfirmDialog(question: string) {
|
||||
if (this.isDialogOpen) {
|
||||
return of(undefined);
|
||||
}
|
||||
|
||||
this.isDialogOpen = true;
|
||||
|
||||
return this._dialog.open(ConfirmDialogComponent, {
|
||||
width: '300px',
|
||||
data: { title: question }
|
||||
})
|
||||
.afterClosed()
|
||||
.pipe(tap(() => this.isDialogOpen = false));
|
||||
}
|
||||
|
||||
|
||||
openQuestionDialog(title: string, control: CmdCtrl) {
|
||||
if (this.isDialogOpen) {
|
||||
return of(control);
|
||||
}
|
||||
|
||||
this.isDialogOpen = true;
|
||||
|
||||
const dialogRef = this._dialog.open(QuestionDialogComponent, {
|
||||
width: '300px',
|
||||
data: {
|
||||
title: title,
|
||||
control: control
|
||||
},
|
||||
panelClass: 'questionDialog',
|
||||
})
|
||||
|
||||
return dialogRef
|
||||
.afterClosed()
|
||||
.pipe(tap(() => this.isDialogOpen = false));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { HttpParams } from '@angular/common/http';
|
||||
import {route } from 'src/app/api/commands.api';
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
|
||||
export class DownloadService {
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
getFile(url:string) {
|
||||
|
||||
const token = 'my JWT';
|
||||
const headers = new HttpHeaders().set('authorization','Bearer '+token);
|
||||
const postparams = new HttpParams().set('fname',url);
|
||||
this.http.post(environment.backend + route + '/file', postparams, {headers, responseType: 'blob' as 'json'}).subscribe(
|
||||
(response: any) =>{
|
||||
let dataType = response.type;
|
||||
let binaryData = [];
|
||||
binaryData.push(response);
|
||||
let downloadLink = document.createElement('a');
|
||||
downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, {type: dataType}));
|
||||
downloadLink.setAttribute('download', url);
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
}
|
||||
)
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LoadingService {
|
||||
isLoading$ = new Subject<boolean>();
|
||||
|
||||
constructor() { }
|
||||
|
||||
startLoading() {
|
||||
this.isLoading$.next(true);
|
||||
}
|
||||
|
||||
stopLoading() {
|
||||
this.isLoading$.next(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
|
||||
import { environment } from "src/environments/environment";
|
||||
|
||||
export enum webSockSrc {
|
||||
softscope = "s".charCodeAt(0),
|
||||
logview = "l".charCodeAt(0),
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
source: webSockSrc;
|
||||
fullbuff: ArrayBuffer;
|
||||
}
|
||||
export const arraybuf_data_offset = 8; // 64 bits (8 bytes) header
|
||||
|
||||
const deserialize = (fullbuff: ArrayBuffer): Message => {
|
||||
const header = new DataView(fullbuff, 0, arraybuf_data_offset); //header
|
||||
return {
|
||||
source: header.getUint8(0),
|
||||
fullbuff: fullbuff
|
||||
};
|
||||
}
|
||||
|
||||
const serialize = (msg: Message): ArrayBuffer => {
|
||||
let buffview = new DataView(msg.fullbuff);
|
||||
buffview.setUint8(0, msg.source); //header
|
||||
return buffview.buffer;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class WebSocketService {
|
||||
|
||||
public subject$: WebSocketSubject<Message>;
|
||||
|
||||
constructor() {
|
||||
this.subject$ = webSocket<Message>({
|
||||
url: 'ws://' + environment.backend + 'softscope',
|
||||
openObserver: { next: () => { console.log('WS connection established') } },
|
||||
closeObserver: { next: () => { console.log('WS connextion closed') } },
|
||||
serializer: msg => serialize(msg),
|
||||
deserializer: msg => deserialize(msg.data),
|
||||
binaryType: 'arraybuffer'
|
||||
});
|
||||
}
|
||||
|
||||
// public get scopeSubject$() {
|
||||
// return this.subject$.multiplex(
|
||||
// () => { console.log('WS scope2 connection established') },
|
||||
// () => { console.log('WS scope2 connection closed') },
|
||||
// msg => msg.source === webSockSrc.softscope,
|
||||
// );
|
||||
// }
|
||||
|
||||
// public get loggerSubject$() {
|
||||
// return this.subject$.multiplex(
|
||||
// () => { console.log('WS logger connection established') },
|
||||
// () => { console.log('WS logger connection closed') },
|
||||
// msg => msg.source === webSockSrc.logview,
|
||||
// );
|
||||
// }
|
||||
|
||||
public send(msg: Message) {
|
||||
console.log('Message sent to websocket: ', msg.fullbuff);
|
||||
this.subject$.next(msg);
|
||||
}
|
||||
|
||||
// public close() {
|
||||
// this.subject$.complete();
|
||||
// }
|
||||
|
||||
// public error() {
|
||||
// this.subject$.error({ code: 4000, reason: 'I think our app just broke!' });
|
||||
// }
|
||||
}
|
||||
|
||||
0
common/utils/websrv/frontend/src/assets/.gitkeep
Normal file
0
common/utils/websrv/frontend/src/assets/.gitkeep
Normal file
@@ -0,0 +1,8 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: true,
|
||||
backend: window.location.hostname + ':' + window.location.port + '/'
|
||||
};
|
||||
19
common/utils/websrv/frontend/src/environments/environment.ts
Normal file
19
common/utils/websrv/frontend/src/environments/environment.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
// backend: 'localhost:8090/',
|
||||
backend: '10.130.163.206:8090/'
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* For easier debugging in development mode, you can import the following file
|
||||
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||
*
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
BIN
common/utils/websrv/frontend/src/favicon.ico
Normal file
BIN
common/utils/websrv/frontend/src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
18
common/utils/websrv/frontend/src/index.html
Normal file
18
common/utils/websrv/frontend/src/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>oai softmodem</title>
|
||||
<base href="/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body class="mat-typography">
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
13
common/utils/websrv/frontend/src/main.ts
Normal file
13
common/utils/websrv/frontend/src/main.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule)
|
||||
.catch((err) => console.error(err));
|
||||
53
common/utils/websrv/frontend/src/polyfills.ts
Normal file
53
common/utils/websrv/frontend/src/polyfills.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||
* will put import in the top of bundle, so user need to create a separate file
|
||||
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||
* into that file, and then add the following code before importing zone.js.
|
||||
* import './zone-flags';
|
||||
*
|
||||
* The flags allowed in zone-flags.ts are listed here.
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
10
common/utils/websrv/frontend/src/styles.css
Normal file
10
common/utils/websrv/frontend/src/styles.css
Normal file
@@ -0,0 +1,10 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Roboto, 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
23
common/utils/websrv/frontend/src/test.ts
Normal file
23
common/utils/websrv/frontend/src/test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp,
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
10
common/utils/websrv/frontend/tsconfig.app.json
Normal file
10
common/utils/websrv/frontend/tsconfig.app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": ["src/main.ts", "src/polyfills.ts"],
|
||||
"include": ["src/**/*.d.ts"]
|
||||
}
|
||||
30
common/utils/websrv/frontend/tsconfig.json
Normal file
30
common/utils/websrv/frontend/tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2020",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
10
common/utils/websrv/frontend/tsconfig.spec.json
Normal file
10
common/utils/websrv/frontend/tsconfig.spec.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": ["jasmine"]
|
||||
},
|
||||
"files": ["src/test.ts", "src/polyfills.ts"],
|
||||
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
|
||||
}
|
||||
1041
common/utils/websrv/websrv.c
Normal file
1041
common/utils/websrv/websrv.c
Normal file
File diff suppressed because it is too large
Load Diff
151
common/utils/websrv/websrv.h
Normal file
151
common/utils/websrv/websrv.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file common/utils/websrv/websrv.h
|
||||
* \brief: implementation of web API
|
||||
* \author Francois TABURET
|
||||
* \date 2022
|
||||
* \version 0.1
|
||||
* \company NOKIA BellLabs France
|
||||
* \email: francois.taburet@nokia-bell-labs.com
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#ifndef WEBSRV_H
|
||||
#define WEBSRV_H
|
||||
|
||||
#define WEBSRV_MODNAME "websrv"
|
||||
|
||||
#define WEBSRV_PORT 8090
|
||||
/* websrv_printf_t is an internal structure storing messages while processing a request */
|
||||
/* The meaage is used to fill a response body */
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex; // protect the message betwween the websrv_printf_start and websrv_print_end calls
|
||||
struct _u_response * response; // the ulfius response structure, used to send the message
|
||||
char *buff; // a buffer to store the message, allocated in websrv_printf_start, free in websrv_print_end
|
||||
int buffsize; //
|
||||
char *buffptr; // pointer to free portion of buff
|
||||
} websrv_printf_t;
|
||||
|
||||
/* websrv_params_t is an internal structure storing all the current parameters and */
|
||||
/* global variables used by the web server */
|
||||
typedef struct {
|
||||
struct _u_instance instance; // ulfius (web server) instance
|
||||
struct _websocket_manager * wm; // web socket instance
|
||||
unsigned int dbglvl; // debug level of the server
|
||||
int priority; // server running priority
|
||||
unsigned int listenport; // ip port the telnet server is listening on
|
||||
unsigned int listenaddr; // ip address the telnet server is listening on
|
||||
unsigned int listenstdin; // enable command input from stdin
|
||||
char *url; // url for the main (initial) web page
|
||||
char *certfile; // cert file
|
||||
char *keyfile; // key file
|
||||
char *rootcafile; // root ca file
|
||||
void *telnetparams; // pointer to telnet server parameters type is telnetsrv_params_t, don't want to enforce telnet include here
|
||||
} websrv_params_t;
|
||||
|
||||
#define WEBSOCK_SRC_SCOPE 's'
|
||||
typedef struct {
|
||||
unsigned char src; // message source
|
||||
unsigned char msgtype; // message type
|
||||
unsigned char msgseg; // message segment number
|
||||
unsigned char chartid; // identify chart (scope window)
|
||||
unsigned char datasetid; // identify dataset in chart
|
||||
unsigned char update; // should chart be updated
|
||||
unsigned char hdr_unused[2]; // 2 unused char
|
||||
} websrv_msg_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
websrv_msg_hdr_t header;
|
||||
char data[1408]; // 64*22
|
||||
} websrv_msg_t;
|
||||
#define MAX_NIQ_WEBSOCKMSG 180000 //max number of 16 bits iq's in pre-allocated buffer
|
||||
#define MAX_LLR_WEBSOCKMSG (MAX_NIQ_WEBSOCKMSG*2) //max number of 8 bits llr's in pre-allocated buffer
|
||||
|
||||
typedef struct {
|
||||
websrv_msg_hdr_t header;
|
||||
int16_t data_xy[MAX_NIQ_WEBSOCKMSG*2]; // data buffer
|
||||
} websrv_scopedata_msg_t;
|
||||
#define WEBSOCK_HEADSIZE (offsetof(websrv_msg_t, data))
|
||||
|
||||
#define SCOPE_STATUSMASK_UNKNOWN 0 // websocket initialized, no scope request received
|
||||
#define SCOPE_STATUSMASK_AVAILABLE 1 // scope can be started (available in exec and not started with other if */
|
||||
#define SCOPE_STATUSMASK_STARTED 2 // scope running
|
||||
#define SCOPE_STATUSMASK_DATAACK 4 // wait for data message acknowledge before sending
|
||||
#define SCOPE_STATUSMASK_DISABLED (1LL<<63) // scope disabled (running with xform interface or not implemented in exec)
|
||||
|
||||
/* values for websocket message type */
|
||||
/* websocket softscope message: */
|
||||
#define SCOPEMSG_TYPE_STATUSUPD 1 // scope status: available, started....
|
||||
#define SCOPEMSG_TYPE_REFRATE 2 // scope refresh delay
|
||||
#define SCOPEMSG_TYPE_TIME 3 // time
|
||||
#define SCOPEMSG_TYPE_DATA 10 // graph data
|
||||
#define SCOPEMSG_TYPE_DATAACK 11 // graph data reception and processing acknowledge
|
||||
#define SCOPEMSG_TYPE_DEFINEWINDOW 20 // scope window definition
|
||||
typedef struct {
|
||||
uint64_t statusmask; //
|
||||
uint32_t refrate; // in 100 ms
|
||||
void *scopeform; // OAI_phy_scope_t pointer returned by create_phy_scope_xxx functions
|
||||
void *scopedata; // scopeData_t pointer, filled at init time, contains pointers and functions to retrieve softmodem data
|
||||
uint32_t selectedTarget; // index to UE/gNB
|
||||
int xmin; // iq view data limit
|
||||
int xmax;
|
||||
int ymin;
|
||||
int ymax;
|
||||
int llr_ythresh; // llrview llr threshold
|
||||
int llrxmin; //llr view x limits
|
||||
int llrxmax;
|
||||
} websrv_scope_params_t;
|
||||
|
||||
/*------------------------------------------------------------------------------------------------*/
|
||||
/* web server utilities: */
|
||||
|
||||
extern void websrv_printjson(char * label, json_t *jsonobj); //debug: dump a json object
|
||||
extern void websrv_jbody( struct _u_response * response, json_t *jbody); // add a json body in a http response
|
||||
|
||||
extern void websrv_printf_start(struct _u_response * response, int buffsize ); // start a printf, lock the buffer
|
||||
extern void websrv_printf( const char *message, ...); // add characters in the printf locked buffer
|
||||
extern void websrv_printf_end(int httpstatus ); // add the printf buffer in the body of a http response, unlock the buffer
|
||||
extern void websrv_dump_request(char *label, const struct _u_request *request); // debug: dump a http request
|
||||
extern int websrv_string_response(char *astring, struct _u_response * response, int httpstatus) ; // add a string in a http response
|
||||
|
||||
/* webserver API: */
|
||||
extern int websrv_init_websocket(websrv_params_t *websrvparams,char *module);
|
||||
extern void websrv_websocket_send_message(char msg_src, char msg_type, char *msg_data, struct _websocket_manager * websocket_manager);
|
||||
|
||||
extern void websrv_websocket_process_scopemessage(char msg_type, char *msg_data, struct _websocket_manager * websocket_manager);
|
||||
extern int websrv_callback_okset_softmodem_cmdvar(const struct _u_request * request, struct _u_response * response, void * user_data);
|
||||
extern int websrv_add_endpoint( char **http_method, int num_method, const char * url_prefix,const char * url_format,
|
||||
int (* callback_function[])(const struct _u_request * request,
|
||||
struct _u_response * response,
|
||||
void * user_data),
|
||||
void * user_data);
|
||||
|
||||
/* scope interface API: */
|
||||
extern void websrv_init_scope(websrv_params_t *websrvparams) ;
|
||||
extern void websrv_scope_ws_cb(void *user_data);
|
||||
extern int websrv_scope_manager(uint64_t lcount,websrv_params_t *websrvparams);
|
||||
extern void websrv_scope_senddata(int numd,int dsize, websrv_scopedata_msg_t *msg);
|
||||
extern websrv_scope_params_t *websrv_scope_getparams(void);
|
||||
extern void websrv_scope_stop(void);
|
||||
/*-----------------------------------------------------------------------------------------------------------*/
|
||||
#endif
|
||||
67
common/utils/websrv/websrv_CMakeLists.txt
Normal file
67
common/utils/websrv/websrv_CMakeLists.txt
Normal file
@@ -0,0 +1,67 @@
|
||||
if ( "${OPENAIR_CMAKE}" STREQUAL "")
|
||||
message( FATAL_ERROR "oai Environment variables not set")
|
||||
endif ( "${OPENAIR_CMAKE}" STREQUAL "")
|
||||
set(WEBSRVROOT ${OPENAIR_DIR}/common/utils/websrv )
|
||||
set (WBACK TRUE)
|
||||
set (WFRONT TRUE)
|
||||
# websrv dependencies
|
||||
#set( ULFIUS "")
|
||||
find_library(ULFIUS NAMES "libulfius.so" NO_CACHE)
|
||||
if ("${ULFIUS}" STREQUAL "")
|
||||
message( FATAL_ERROR "ulfius library (https://github.com/babelouest/ulfius) not found, install libulfius-dev (ubuntu) ")
|
||||
set (WBACK FALSE)
|
||||
endif("${ULFIUS}" STREQUAL "")
|
||||
|
||||
find_library(JSON NAMES "libjansson.so" NO_CACHE )
|
||||
if ("${JSON}" STREQUAL "")
|
||||
message( ERROR "libjansson not found, install libjansson-dev for ubuntu, jansson-devel for fedora")
|
||||
set (WBACK FALSE)
|
||||
endif("${JSON}" STREQUAL "")
|
||||
|
||||
#set (NPM "")
|
||||
find_program(NPM NAMES npm NO_CACHE)
|
||||
if ("${NPM}" STREQUAL "")
|
||||
message( ERROR " npm is not installed, frontend won't be built. Possibly install npm, package is available for ubuntu and fedora")
|
||||
endif("${NPM}" STREQUAL "")
|
||||
|
||||
|
||||
# build the backend ( the embedded web server)
|
||||
|
||||
set(WEBSRV_SOURCE
|
||||
${WEBSRVROOT}/websrv.c ${WEBSRVROOT}/websrv_websockets.c
|
||||
${WEBSRVROOT}/websrv_scope.c ${WEBSRVROOT}/websrv_noforms.c
|
||||
${OPENAIR_DIR}/openair1/PHY/TOOLS/nr_phy_scope.c
|
||||
)
|
||||
|
||||
if ( ${WBACK} )
|
||||
add_library(websrv MODULE ${WEBSRV_SOURCE} )
|
||||
target_link_libraries(websrv PRIVATE ulfius jansson)
|
||||
target_compile_definitions(websrv PUBLIC WEBSRVSCOPE)
|
||||
endif ( ${WBACK} )
|
||||
|
||||
# build the frontend ( loaded from web server by browsers)
|
||||
add_custom_target (
|
||||
websrvfront_installjsdep
|
||||
WORKING_DIRECTORY ${WEBSRVROOT}/frontend
|
||||
COMMAND npm install
|
||||
DEPENDS ${WEBSRVROOT}/frontend/package-lock.json
|
||||
)
|
||||
|
||||
add_custom_target (
|
||||
websrvfront
|
||||
WORKING_DIRECTORY ${WEBSRVROOT}/frontend
|
||||
COMMAND npm run build
|
||||
#COMMAND npm run builddev
|
||||
DEPENDS websrvfront_installjsdep
|
||||
)
|
||||
#install built files, required at exec time
|
||||
if ( ${WBACK} )
|
||||
install(TARGETS websrv DESTINATION bin)
|
||||
endif ( ${WBACK} )
|
||||
|
||||
if (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
|
||||
add_custom_command(TARGET websrvfront
|
||||
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${WEBSRVROOT}/frontend/dist/softmodem-ngx ${OPENAIR_CMAKE}/ran_build/build/websrv
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${WEBSRVROOT}/frontend/dist/softmodem-ngx ${OPENAIR_TARGETS}/bin/websrv
|
||||
COMMENT "Moving frontend files to:\n ${OPENAIR_CMAKE}/ran_build/build/websrv\n ${OPENAIR_TARGETS}/bin/websrv" )
|
||||
endif (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user