mirror of https://github.com/pvnis/srsRAN_4G.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
563 lines
17 KiB
C++
563 lines
17 KiB
C++
/**
|
|
*
|
|
* \section COPYRIGHT
|
|
*
|
|
* Copyright 2013-2020 Software Radio Systems Limited
|
|
*
|
|
* By using this file, you agree to the terms and conditions set
|
|
* forth in the LICENSE file which can be found at the top level of
|
|
* the distribution.
|
|
*
|
|
*/
|
|
|
|
/*! \brief This class provides helpers for encoding JSON-formated responses
|
|
* for TTCN3.
|
|
*
|
|
*/
|
|
|
|
#ifndef SRSUE_TTCN3_HELPERS_H
|
|
#define SRSUE_TTCN3_HELPERS_H
|
|
|
|
#include "rapidjson/document.h" // rapidjson's DOM-style API
|
|
#include "rapidjson/prettywriter.h" // for stringify JSON
|
|
#include "srslte/asn1/asn1_utils.h"
|
|
#include "srslte/common/common.h"
|
|
#include <algorithm>
|
|
#include <assert.h>
|
|
#include <bitset>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace std;
|
|
using namespace rapidjson;
|
|
using namespace srslte;
|
|
|
|
class ttcn3_helpers
|
|
{
|
|
public:
|
|
typedef struct {
|
|
bool now; ///< If set to false, the TTI field contains a valid TTI
|
|
uint32_t tti;
|
|
} timing_info_t;
|
|
|
|
typedef struct {
|
|
uint8_t rb_id;
|
|
bool rb_is_srb;
|
|
bool ul_value_valid;
|
|
uint16_t ul_value;
|
|
bool dl_value_valid;
|
|
uint16_t dl_value;
|
|
} pdcp_count_t;
|
|
typedef std::vector<ttcn3_helpers::pdcp_count_t> pdcp_count_map_t;
|
|
|
|
static std::string get_ctrl_cnf(const std::string protocol_, const std::string version_, const std::string addr_)
|
|
{
|
|
Document resp;
|
|
resp.SetObject();
|
|
|
|
// Create members of common object
|
|
Value ctrl(kObjectType);
|
|
|
|
// The connection ID object
|
|
Value conn_id(kObjectType);
|
|
|
|
// Protocol
|
|
Value protocol(protocol_.c_str(), resp.GetAllocator());
|
|
conn_id.AddMember("Protocol", protocol, resp.GetAllocator());
|
|
|
|
// Version
|
|
Value ipAddr(kObjectType);
|
|
Value version(version_.c_str(), resp.GetAllocator());
|
|
Value addr(addr_.c_str(), resp.GetAllocator());
|
|
|
|
if (version_ == "V4") {
|
|
Value v4(kObjectType);
|
|
v4.AddMember("Addr", addr, resp.GetAllocator());
|
|
ipAddr.AddMember("V4", v4, resp.GetAllocator());
|
|
} else if (version_ == "V6") {
|
|
Value v6(kObjectType);
|
|
v6.AddMember("Addr", addr, resp.GetAllocator());
|
|
ipAddr.AddMember("V6", v6, resp.GetAllocator());
|
|
} else {
|
|
fprintf(stderr, "Unsupported protocol version: %s.\n", version_.c_str());
|
|
return std::string("");
|
|
}
|
|
|
|
// Local
|
|
Value local(kObjectType);
|
|
local.AddMember("IpAddr", ipAddr, resp.GetAllocator());
|
|
|
|
if (protocol_ == "udp") {
|
|
local.AddMember("Port", 33, resp.GetAllocator());
|
|
}
|
|
|
|
// Remote
|
|
Value rem(kObjectType);
|
|
|
|
// Add members to Connection ID
|
|
conn_id.AddMember("Local", local, resp.GetAllocator());
|
|
conn_id.AddMember("Remote", rem, resp.GetAllocator());
|
|
|
|
// The Indication object
|
|
Value ind(kObjectType);
|
|
Value ind_protocol_val(kObjectType);
|
|
ind_protocol_val.AddMember("SocketCnf", true, resp.GetAllocator());
|
|
if (protocol_ == "udp") {
|
|
ind.AddMember("UDP", ind_protocol_val, resp.GetAllocator());
|
|
} else if (protocol_ == "icmpv6") {
|
|
ind.AddMember("ICMP", ind_protocol_val, resp.GetAllocator());
|
|
} else {
|
|
fprintf(stderr, "Unsupported protocol %s.\n", protocol_.c_str());
|
|
return std::string("");
|
|
}
|
|
|
|
ctrl.AddMember("ConnectionId", conn_id, resp.GetAllocator());
|
|
ctrl.AddMember("Ind", ind, resp.GetAllocator());
|
|
|
|
resp.AddMember("CTRL", ctrl, resp.GetAllocator());
|
|
|
|
// JSON-ize
|
|
StringBuffer buffer;
|
|
Writer<StringBuffer> writer(buffer);
|
|
resp.Accept(writer);
|
|
|
|
// Return as std::string
|
|
return std::string(buffer.GetString());
|
|
}
|
|
|
|
static std::string get_drbmux_common_ind_cnf()
|
|
{
|
|
Document resp;
|
|
resp.SetObject();
|
|
|
|
resp.AddMember("Confirm", true, resp.GetAllocator());
|
|
|
|
// JSON-ize
|
|
StringBuffer buffer;
|
|
Writer<StringBuffer> writer(buffer);
|
|
resp.Accept(writer);
|
|
|
|
// Return as std::string
|
|
return std::string(buffer.GetString());
|
|
}
|
|
|
|
static std::string get_pdcp_count_response(const std::string cell_,
|
|
const std::vector<ttcn3_helpers::pdcp_count_t>& bearers)
|
|
{
|
|
Document resp;
|
|
resp.SetObject();
|
|
|
|
// Create members of common object
|
|
|
|
// Cell
|
|
Value cell(cell_.c_str(), resp.GetAllocator());
|
|
|
|
// RoutingInfo
|
|
Value routing_info(kObjectType);
|
|
routing_info.AddMember("None", true, resp.GetAllocator());
|
|
|
|
// TimingInfo
|
|
Value timing_info(kObjectType);
|
|
timing_info.AddMember("Now", true, resp.GetAllocator());
|
|
|
|
// Result
|
|
Value result(kObjectType);
|
|
result.AddMember("Success", true, resp.GetAllocator());
|
|
|
|
// Now, create the common object itself and add members
|
|
Value common(kObjectType);
|
|
common.AddMember("CellId", cell, resp.GetAllocator());
|
|
common.AddMember("RoutingInfo", routing_info, resp.GetAllocator());
|
|
common.AddMember("TimingInfo", timing_info, resp.GetAllocator());
|
|
common.AddMember("Result", result, resp.GetAllocator());
|
|
|
|
// Add all bearers
|
|
rapidjson::Value bearer_array(rapidjson::kArrayType);
|
|
std::vector<ttcn3_helpers::pdcp_count_t>::const_iterator it;
|
|
for (it = bearers.begin(); it != bearers.end(); ++it) {
|
|
// SRB0
|
|
Value radio_bearer_id(kObjectType);
|
|
radio_bearer_id.AddMember(it->rb_is_srb ? "Srb" : "Drb", it->rb_id, resp.GetAllocator());
|
|
|
|
Value ul(kObjectType);
|
|
Value rb_format_ul(it->rb_is_srb ? "PdcpCount_Srb" : "PdcpCount_DrbLongSQN", resp.GetAllocator());
|
|
ul.AddMember("Format", rb_format_ul, resp.GetAllocator());
|
|
|
|
// convert int to sstream, then to RapidJSON value and add as member
|
|
stringstream value_ss;
|
|
value_ss << std::bitset<32>(it->ul_value);
|
|
Value ul_value(value_ss.str().c_str(), resp.GetAllocator());
|
|
ul.AddMember("Value", ul_value, resp.GetAllocator());
|
|
|
|
Value dl(kObjectType);
|
|
Value rb_format_dl(it->rb_is_srb ? "PdcpCount_Srb" : "PdcpCount_DrbLongSQN", resp.GetAllocator());
|
|
dl.AddMember("Format", rb_format_dl, resp.GetAllocator());
|
|
|
|
// do the same conversion for the DL value
|
|
value_ss.str("");
|
|
value_ss.clear();
|
|
value_ss << std::bitset<32>(it->dl_value);
|
|
Value dl_value(value_ss.str().c_str(), resp.GetAllocator());
|
|
dl.AddMember("Value", dl_value, resp.GetAllocator());
|
|
|
|
// The Get object combines the information of all requested bearer
|
|
Value get_element(kObjectType);
|
|
get_element.AddMember("RadioBearerId", radio_bearer_id, resp.GetAllocator());
|
|
get_element.AddMember("UL", ul, resp.GetAllocator());
|
|
get_element.AddMember("DL", dl, resp.GetAllocator());
|
|
|
|
bearer_array.PushBack(get_element, resp.GetAllocator());
|
|
}
|
|
|
|
// The confirm object
|
|
Value confirm_key(kObjectType);
|
|
|
|
// Add array
|
|
confirm_key.AddMember("Get", bearer_array, resp.GetAllocator());
|
|
|
|
Value confirm(kObjectType);
|
|
confirm.AddMember("PdcpCount", confirm_key, resp.GetAllocator());
|
|
|
|
resp.AddMember("Common", common, resp.GetAllocator());
|
|
resp.AddMember("Confirm", confirm, resp.GetAllocator());
|
|
|
|
// JSON-ize
|
|
StringBuffer buffer;
|
|
Writer<StringBuffer> writer(buffer);
|
|
resp.Accept(writer);
|
|
|
|
// Return as std::string
|
|
return std::string(buffer.GetString());
|
|
}
|
|
|
|
static std::string get_basic_sys_req_cnf(const std::string cell_, const std::string confirm_key_)
|
|
{
|
|
Document resp;
|
|
resp.SetObject();
|
|
|
|
// Create members of common object
|
|
|
|
// Cell
|
|
Value cell(cell_.c_str(), resp.GetAllocator());
|
|
|
|
// RoutingInfo
|
|
Value routing_info(kObjectType);
|
|
routing_info.AddMember("None", true, resp.GetAllocator());
|
|
|
|
// TimingInfo
|
|
Value timing_info(kObjectType);
|
|
timing_info.AddMember("Now", true, resp.GetAllocator());
|
|
|
|
// Result
|
|
Value result(kObjectType);
|
|
result.AddMember("Success", true, resp.GetAllocator());
|
|
|
|
// Now, create the common object itself and add members
|
|
Value common(kObjectType);
|
|
common.AddMember("CellId", cell, resp.GetAllocator());
|
|
common.AddMember("RoutingInfo", routing_info, resp.GetAllocator());
|
|
common.AddMember("TimingInfo", timing_info, resp.GetAllocator());
|
|
common.AddMember("Result", result, resp.GetAllocator());
|
|
|
|
// The confirm object
|
|
Value confirm_key(confirm_key_.c_str(), resp.GetAllocator());
|
|
Value confirm_val(true);
|
|
Value confirm(kObjectType);
|
|
confirm.AddMember(confirm_key, confirm_val, resp.GetAllocator());
|
|
|
|
resp.AddMember("Common", common, resp.GetAllocator());
|
|
resp.AddMember("Confirm", confirm, resp.GetAllocator());
|
|
|
|
// JSON-ize
|
|
StringBuffer buffer;
|
|
Writer<StringBuffer> writer(buffer);
|
|
resp.Accept(writer);
|
|
|
|
// Return as std::string
|
|
return std::string(buffer.GetString());
|
|
}
|
|
|
|
static std::string
|
|
get_sys_req_cnf_with_time(const std::string cell_, const std::string confirm_key_, const uint32_t tti)
|
|
{
|
|
Document resp;
|
|
resp.SetObject();
|
|
|
|
// Create members of common object
|
|
|
|
// Cell
|
|
Value cell(cell_.c_str(), resp.GetAllocator());
|
|
|
|
// RoutingInfo
|
|
Value routing_info(kObjectType);
|
|
routing_info.AddMember("None", true, resp.GetAllocator());
|
|
|
|
// TimingInfo
|
|
|
|
// SFN
|
|
uint32_t sfn = tti / 10;
|
|
Value sfn_key(kObjectType);
|
|
sfn_key.AddMember("Number", sfn, resp.GetAllocator());
|
|
|
|
// Actual subframe index
|
|
uint32_t sf_idx = tti % 10;
|
|
Value sf_idx_key(kObjectType);
|
|
sf_idx_key.AddMember("Number", sf_idx, resp.GetAllocator());
|
|
|
|
// Put it all together
|
|
Value subframe_key(kObjectType);
|
|
subframe_key.AddMember("SFN", sfn_key, resp.GetAllocator());
|
|
subframe_key.AddMember("Subframe", sf_idx_key, resp.GetAllocator());
|
|
|
|
Value timing_info(kObjectType);
|
|
timing_info.AddMember("SubFrame", subframe_key, resp.GetAllocator());
|
|
|
|
// Result
|
|
Value result(kObjectType);
|
|
result.AddMember("Success", true, resp.GetAllocator());
|
|
|
|
// Now, create the common object itself and add members
|
|
Value common(kObjectType);
|
|
common.AddMember("CellId", cell, resp.GetAllocator());
|
|
common.AddMember("RoutingInfo", routing_info, resp.GetAllocator());
|
|
common.AddMember("TimingInfo", timing_info, resp.GetAllocator());
|
|
common.AddMember("Result", result, resp.GetAllocator());
|
|
|
|
// The confirm object
|
|
Value confirm_key(confirm_key_.c_str(), resp.GetAllocator());
|
|
Value confirm_val(true);
|
|
Value confirm(kObjectType);
|
|
confirm.AddMember(confirm_key, confirm_val, resp.GetAllocator());
|
|
|
|
resp.AddMember("Common", common, resp.GetAllocator());
|
|
resp.AddMember("Confirm", confirm, resp.GetAllocator());
|
|
|
|
// JSON-ize
|
|
StringBuffer buffer;
|
|
Writer<StringBuffer> writer(buffer);
|
|
resp.Accept(writer);
|
|
|
|
// Return as std::string
|
|
return std::string(buffer.GetString());
|
|
}
|
|
|
|
static bool requires_confirm(Document& document)
|
|
{
|
|
const Value& a = document["Common"];
|
|
|
|
// check cnf flag
|
|
assert(a.HasMember("ControlInfo"));
|
|
const Value& b = a["ControlInfo"];
|
|
assert(b.HasMember("CnfFlag"));
|
|
|
|
const Value& config_flag = b["CnfFlag"];
|
|
assert(config_flag.IsBool());
|
|
|
|
return config_flag.GetBool();
|
|
}
|
|
|
|
static std::string get_cell_name(Document& document)
|
|
{
|
|
const Value& a = document["Common"];
|
|
|
|
assert(a.HasMember("CellId"));
|
|
const Value& cell_id = a["CellId"];
|
|
|
|
return cell_id.GetString();
|
|
}
|
|
|
|
static timing_info_t get_timing_info(Document& document)
|
|
{
|
|
timing_info_t timing = {};
|
|
|
|
// check for Now flag
|
|
if (document.HasMember("Common") && document["Common"].HasMember("TimingInfo") &&
|
|
document["Common"]["TimingInfo"].HasMember("Now")) {
|
|
timing.now = true;
|
|
}
|
|
|
|
if (document.HasMember("Common") && document["Common"].HasMember("TimingInfo") &&
|
|
document["Common"]["TimingInfo"].HasMember("SubFrame") &&
|
|
document["Common"]["TimingInfo"]["SubFrame"].HasMember("SFN") &&
|
|
document["Common"]["TimingInfo"]["SubFrame"]["SFN"].HasMember("Number")) {
|
|
|
|
timing.tti = document["Common"]["TimingInfo"]["SubFrame"]["SFN"]["Number"].GetInt() * 10;
|
|
|
|
// check SF index only
|
|
if (document["Common"]["TimingInfo"]["SubFrame"].HasMember("Subframe") &&
|
|
document["Common"]["TimingInfo"]["SubFrame"]["Subframe"].HasMember("Number")) {
|
|
timing.tti += document["Common"]["TimingInfo"]["SubFrame"]["Subframe"]["Number"].GetInt();
|
|
}
|
|
}
|
|
return timing;
|
|
}
|
|
|
|
static bool get_follow_on_flag(Document& document)
|
|
{
|
|
const Value& a = document["Common"];
|
|
|
|
// check cnf flag
|
|
assert(a.HasMember("ControlInfo"));
|
|
const Value& b = a["ControlInfo"];
|
|
assert(b.HasMember("FollowOnFlag"));
|
|
|
|
const Value& config_flag = b["FollowOnFlag"];
|
|
assert(config_flag.IsBool());
|
|
|
|
return config_flag.GetBool();
|
|
}
|
|
|
|
static std::string
|
|
get_rrc_pdu_ind_for_pdu(uint32_t tti, uint32_t lcid, const std::string cell_, srslte::unique_byte_buffer_t pdubuf)
|
|
{
|
|
Document resp;
|
|
resp.SetObject();
|
|
|
|
// Create members of common object
|
|
|
|
// CellId
|
|
Value cell(cell_.c_str(), resp.GetAllocator());
|
|
|
|
// RoutingInfo
|
|
Value radiobearer_id(kObjectType);
|
|
radiobearer_id.AddMember("Srb", lcid, resp.GetAllocator());
|
|
Value routing_info(kObjectType);
|
|
routing_info.AddMember("RadioBearerId", radiobearer_id, resp.GetAllocator());
|
|
|
|
// TimingInfo
|
|
// SFN
|
|
uint32_t sfn = tti / 10;
|
|
Value sfn_key(kObjectType);
|
|
sfn_key.AddMember("Number", sfn, resp.GetAllocator());
|
|
|
|
// Actual subframe index
|
|
uint32_t sf_idx = tti % 10;
|
|
Value sf_idx_key(kObjectType);
|
|
sf_idx_key.AddMember("Number", sf_idx, resp.GetAllocator());
|
|
|
|
// Put it all together
|
|
Value subframe_key(kObjectType);
|
|
subframe_key.AddMember("SFN", sfn_key, resp.GetAllocator());
|
|
subframe_key.AddMember("Subframe", sf_idx_key, resp.GetAllocator());
|
|
|
|
Value timing_info(kObjectType);
|
|
timing_info.AddMember("SubFrame", subframe_key, resp.GetAllocator());
|
|
|
|
// Status
|
|
Value status(kObjectType);
|
|
status.AddMember("Ok", true, resp.GetAllocator());
|
|
|
|
// Now, create the common object itself and add members
|
|
Value common(kObjectType);
|
|
common.AddMember("CellId", cell, resp.GetAllocator());
|
|
common.AddMember("RoutingInfo", routing_info, resp.GetAllocator());
|
|
common.AddMember("TimingInfo", timing_info, resp.GetAllocator());
|
|
common.AddMember("Status", status, resp.GetAllocator());
|
|
|
|
resp.AddMember("Common", common, resp.GetAllocator());
|
|
|
|
// Add RRC PDU
|
|
std::string hexpdu = asn1::octstring_to_string(pdubuf->msg, pdubuf->N_bytes);
|
|
Value pdu(hexpdu.c_str(), resp.GetAllocator());
|
|
|
|
Value rrcpdu(kObjectType);
|
|
if (lcid == 0) {
|
|
rrcpdu.AddMember("Ccch", pdu, resp.GetAllocator());
|
|
} else {
|
|
rrcpdu.AddMember("Dcch", pdu, resp.GetAllocator());
|
|
}
|
|
|
|
resp.AddMember("RrcPdu", rrcpdu, resp.GetAllocator());
|
|
|
|
// JSON-ize
|
|
StringBuffer buffer;
|
|
Writer<StringBuffer> writer(buffer);
|
|
resp.Accept(writer);
|
|
|
|
// Return as std::string
|
|
return std::string(buffer.GetString());
|
|
}
|
|
|
|
static std::string
|
|
get_drb_common_ind_for_pdu(uint32_t tti, uint32_t lcid, const std::string cell_, srslte::unique_byte_buffer_t drbpdu)
|
|
{
|
|
Document resp;
|
|
resp.SetObject();
|
|
|
|
// Create members of common object
|
|
|
|
// Cell
|
|
Value cell(cell_.c_str(), resp.GetAllocator());
|
|
|
|
// RoutingInfo
|
|
Value radiobearer_id(kObjectType);
|
|
radiobearer_id.AddMember("Drb", lcid - 2, resp.GetAllocator());
|
|
Value routing_info(kObjectType);
|
|
routing_info.AddMember("RadioBearerId", radiobearer_id, resp.GetAllocator());
|
|
|
|
// TimingInfo
|
|
// SFN
|
|
uint32_t sfn = tti / 10;
|
|
Value sfn_key(kObjectType);
|
|
sfn_key.AddMember("Number", sfn, resp.GetAllocator());
|
|
|
|
// Actual subframe index
|
|
uint32_t sf_idx = tti % 10;
|
|
Value sf_idx_key(kObjectType);
|
|
sf_idx_key.AddMember("Number", sf_idx, resp.GetAllocator());
|
|
|
|
// Put it all together
|
|
Value subframe_key(kObjectType);
|
|
subframe_key.AddMember("SFN", sfn_key, resp.GetAllocator());
|
|
subframe_key.AddMember("Subframe", sf_idx_key, resp.GetAllocator());
|
|
|
|
Value timing_info(kObjectType);
|
|
timing_info.AddMember("SubFrame", subframe_key, resp.GetAllocator());
|
|
|
|
// Status
|
|
Value status(kObjectType);
|
|
status.AddMember("Ok", true, resp.GetAllocator());
|
|
|
|
// Now, create the common object itself and add members
|
|
Value common(kObjectType);
|
|
common.AddMember("CellId", cell, resp.GetAllocator());
|
|
common.AddMember("RoutingInfo", routing_info, resp.GetAllocator());
|
|
common.AddMember("TimingInfo", timing_info, resp.GetAllocator());
|
|
common.AddMember("Status", status, resp.GetAllocator());
|
|
|
|
resp.AddMember("Common", common, resp.GetAllocator());
|
|
|
|
// Add the user plane data
|
|
std::string hexdrb = asn1::octstring_to_string(drbpdu->msg, drbpdu->N_bytes);
|
|
Value sdu(hexdrb.c_str(), resp.GetAllocator());
|
|
|
|
Value pdcpsdu(kArrayType);
|
|
pdcpsdu.PushBack(sdu, resp.GetAllocator());
|
|
|
|
Value pdusdulist(kObjectType);
|
|
pdusdulist.AddMember("PdcpSdu", pdcpsdu, resp.GetAllocator());
|
|
|
|
Value sfdata(kObjectType);
|
|
sfdata.AddMember("PduSduList", pdusdulist, resp.GetAllocator());
|
|
|
|
// FIXME: Get real no. of TTIs for transmission
|
|
sfdata.AddMember("NoOfTTIs", 1, resp.GetAllocator());
|
|
|
|
Value uplane(kObjectType);
|
|
uplane.AddMember("SubframeData", sfdata, resp.GetAllocator());
|
|
|
|
resp.AddMember("U_Plane", uplane, resp.GetAllocator());
|
|
|
|
// JSON-ize
|
|
StringBuffer buffer;
|
|
Writer<StringBuffer> writer(buffer);
|
|
resp.Accept(writer);
|
|
|
|
// Return as std::string
|
|
return std::string(buffer.GetString());
|
|
}
|
|
};
|
|
|
|
#endif // SRSUE_TTCN3_HELPERS_H
|