pdu: refactor MAC PDU class

this patch refactors the MAC PDU class, the main changes are:

* add to_string() method to pretty print PDU and subheaders
  This allows to have a single log entry per MAC PDU with all its
  contents.
  It removes the C-style fprint() method

* Simplity payload vs. w_payload_ce
  Before we've used payload when reading the PDU and w_payload_ce
  as a buffer when writing. In all getters we needed to differentiate
  between both. Now payload points to w_payload_ce initially and is
  only updated when parsing a new PDU.

* add various helpers, e.g. to get subheader index, update a BSR, ..

* fix PDU test to use new to_string() method
This commit is contained in:
Andre Puschmann 2020-08-31 23:31:45 +02:00
parent 92d76a5eb6
commit d48bc8837e
3 changed files with 129 additions and 114 deletions

View File

@ -139,13 +139,13 @@ public:
{}
virtual ~pdu() = default;
void fprint(FILE* stream)
std::string to_string()
{
fprintf(stream, "Number of Subheaders: %d\n", nof_subheaders);
std::stringstream ss;
for (int i = 0; i < nof_subheaders; i++) {
fprintf(stream, " -- Subheader %d: ", i);
subheaders[i].fprint(stream);
ss << subheaders[i].to_string() << " ";
}
return ss.str();
}
/* Resets the Read/Write position and remaining PDU length */
@ -187,6 +187,8 @@ public:
}
}
int get_current_idx() { return cur_idx; }
void del_subh()
{
if (nof_subheaders > 0) {
@ -206,6 +208,16 @@ public:
}
}
// Get subheader at specified index
SubH* get(uint32_t idx)
{
if (nof_subheaders > 0 && idx >= 0 && idx < (uint32_t)nof_subheaders) {
return &subheaders[idx];
} else {
return nullptr;
}
}
bool is_ul() { return pdu_is_ul; }
uint8_t* get_current_sdu_ptr() { return &buffer_tx->msg[buffer_tx->N_bytes]; }
@ -281,7 +293,7 @@ public:
virtual void read_payload(uint8_t** ptr) = 0;
virtual void write_subheader(uint8_t** ptr, bool is_last) = 0;
virtual void write_payload(uint8_t** ptr) = 0;
virtual void fprint(FILE* stream) = 0;
virtual std::string to_string() = 0;
pdu<SubH>* parent = nullptr;
@ -324,7 +336,7 @@ public:
uint8_t get_ta_cmd();
uint8_t get_activation_deactivation_cmd();
float get_phr();
int get_bsr(uint32_t buff_size_idx[4], uint32_t buff_size_bytes[4]);
uint32_t get_bsr(uint32_t buff_size_idx[4], uint32_t buff_size_bytes[4]);
bool get_next_mch_sched_info(uint8_t* lcid, uint16_t* mtch_stop);
@ -336,6 +348,7 @@ public:
int set_sdu(uint32_t lcid, uint32_t requested_bytes, read_pdu_interface* sdu_itf);
bool set_c_rnti(uint16_t crnti);
bool set_bsr(uint32_t buff_size[4], ul_sch_lcid format);
void update_bsr(uint32_t buff_size[4], ul_sch_lcid format);
bool set_con_res_id(uint64_t con_res_id);
bool set_ta_cmd(uint8_t ta_cmd);
bool set_scell_activation_cmd(const std::array<bool, SRSLTE_MAX_CARRIERS>& active_scell_idxs);
@ -345,7 +358,7 @@ public:
void set_type(subh_type type_);
void init();
void fprint(FILE* stream);
std::string to_string();
bool set_next_mch_sched_info(uint8_t lcid, uint16_t mtch_stop);
@ -353,7 +366,7 @@ protected:
static const int MAX_CE_PAYLOAD_LEN = 8;
uint32_t lcid = 0;
int nof_bytes = 0;
uint8_t* payload = nullptr;
uint8_t* payload = w_payload_ce; // points to write buffer initially
uint8_t w_payload_ce[64] = {};
uint8_t nof_mch_sched_ce = 0;
uint8_t cur_mch_sched_ce = 0;
@ -383,7 +396,7 @@ public:
static uint32_t size_header_sdu(uint32_t nbytes);
bool update_space_ce(uint32_t nbytes, bool var_len = false);
bool update_space_sdu(uint32_t nbytes);
void fprint(FILE* stream);
std::string to_string();
};
class rar_subh : public subh<rar_subh>
@ -421,7 +434,7 @@ public:
void set_sched_grant(uint8_t grant[RAR_GRANT_LEN]);
void init();
void fprint(FILE* stream);
std::string to_string();
private:
uint8_t grant[RAR_GRANT_LEN];
@ -441,7 +454,7 @@ public:
uint8_t get_backoff();
bool write_packet(uint8_t* ptr);
void fprint(FILE* stream);
std::string to_string();
private:
bool has_backoff_indicator;

View File

@ -182,10 +182,11 @@ bool lcid_t::is_sdu() const
* SCH PDU
*************************/
void sch_pdu::fprint(FILE* stream)
std::string sch_pdu::to_string()
{
fprintf(stream, "MAC SDU for UL/DL-SCH. ");
pdu::fprint(stream);
std::stringstream ss;
ss << (is_ul() ? "UL " : "DL ") << pdu::to_string();
return ss.str();
}
void sch_pdu::parse_packet(uint8_t* ptr)
@ -327,7 +328,7 @@ uint8_t* sch_pdu::write_packet(srslte::log_ref log_h)
log_h->debug("Writing MAC PDU with padding only (%d B)\n", pdu_len);
}
/* Sanity check and print if error */
// Sanity check and print if error
if (log_h) {
log_h->debug("Wrote PDU: pdu_len=%d, header_and_ce=%d (%d+%d), nof_subh=%d, last_sdu=%d, onepad=%d, multi=%d\n",
pdu_len,
@ -400,7 +401,9 @@ int sch_pdu::get_pdu_len()
uint32_t sch_pdu::size_header_sdu(uint32_t nbytes)
{
if (nbytes < 128) {
if (nbytes == 0) {
return 0;
} else if (nbytes < 128) {
return 2;
} else {
return 3;
@ -456,7 +459,7 @@ bool sch_pdu::update_space_sdu(uint32_t nbytes)
int sch_pdu::get_sdu_space()
{
int ret = 0;
int32_t ret = 0;
if (last_sdu_idx < 0) {
ret = rem_len - 1;
} else {
@ -468,9 +471,10 @@ int sch_pdu::get_sdu_space()
void sch_subh::init()
{
srslte_vec_u8_zero(w_payload_ce, 64);
payload = w_payload_ce;
lcid = 0;
nof_bytes = 0;
payload = NULL;
nof_mch_sched_ce = 0;
cur_mch_sched_ce = 0;
}
@ -541,97 +545,68 @@ bool sch_subh::is_var_len_ce()
uint16_t sch_subh::get_c_rnti()
{
if (payload) {
return (uint16_t)payload[0] << 8 | payload[1];
} else {
return (uint16_t)w_payload_ce[0] << 8 | w_payload_ce[1];
}
return (uint16_t)payload[0] << 8 | payload[1];
}
uint64_t sch_subh::get_con_res_id()
{
if (payload) {
return ((uint64_t)payload[5]) | (((uint64_t)payload[4]) << 8) | (((uint64_t)payload[3]) << 16) |
(((uint64_t)payload[2]) << 24) | (((uint64_t)payload[1]) << 32) | (((uint64_t)payload[0]) << 40);
} else {
return ((uint64_t)w_payload_ce[5]) | (((uint64_t)w_payload_ce[4]) << 8) | (((uint64_t)w_payload_ce[3]) << 16) |
(((uint64_t)w_payload_ce[2]) << 24) | (((uint64_t)w_payload_ce[1]) << 32) |
(((uint64_t)w_payload_ce[0]) << 40);
return 0;
}
return ((uint64_t)payload[5]) | (((uint64_t)payload[4]) << 8) | (((uint64_t)payload[3]) << 16) |
(((uint64_t)payload[2]) << 24) | (((uint64_t)payload[1]) << 32) | (((uint64_t)payload[0]) << 40);
}
float sch_subh::get_phr()
{
if (payload) {
return (float)(payload[0] & 0x3f) - 23;
} else {
return (float)(w_payload_ce[0] & 0x3f) - 23;
}
return (float)(payload[0] & 0x3f) - 23;
}
int sch_subh::get_bsr(uint32_t buff_size_idx[4], uint32_t buff_size_bytes[4])
uint32_t sch_subh::get_bsr(uint32_t buff_size_idx[4], uint32_t buff_size_bytes[4])
{
if (payload) {
uint32_t nonzero_lcg = 0;
if (ul_sch_ce_type() == ul_sch_lcid::LONG_BSR) {
buff_size_idx[0] = (payload[0] & 0xFC) >> 2;
buff_size_idx[1] = (payload[0] & 0x03) << 4 | (payload[1] & 0xF0) >> 4;
buff_size_idx[2] = (payload[1] & 0x0F) << 4 | (payload[1] & 0xC0) >> 6;
buff_size_idx[3] = (payload[2] & 0x3F);
} else {
nonzero_lcg = (payload[0] & 0xc0) >> 6;
buff_size_idx[nonzero_lcg % 4] = payload[0] & 0x3f;
}
for (int i = 0; i < 4; i++) {
if (buff_size_idx[i] > 0) {
if (buff_size_idx[i] < 63) {
buff_size_bytes[i] = btable[1 + buff_size_idx[i]];
} else {
buff_size_bytes[i] = btable[63];
}
uint32_t nonzero_lcg = 0;
if (ul_sch_ce_type() == ul_sch_lcid::LONG_BSR) {
buff_size_idx[0] = (payload[0] & 0xFC) >> 2;
buff_size_idx[1] = (payload[0] & 0x03) << 4 | (payload[1] & 0xF0) >> 4;
buff_size_idx[2] = (payload[1] & 0x0F) << 4 | (payload[1] & 0xC0) >> 6;
buff_size_idx[3] = (payload[2] & 0x3F);
} else {
nonzero_lcg = (payload[0] & 0xc0) >> 6;
buff_size_idx[nonzero_lcg % 4] = payload[0] & 0x3f;
}
for (int i = 0; i < 4; i++) {
if (buff_size_idx[i] > 0) {
if (buff_size_idx[i] < 63) {
buff_size_bytes[i] = btable[1 + buff_size_idx[i]];
} else {
buff_size_bytes[i] = btable[63];
}
}
return nonzero_lcg;
} else {
return -1;
}
return nonzero_lcg;
}
bool sch_subh::get_next_mch_sched_info(uint8_t* lcid_, uint16_t* mtch_stop)
{
uint16_t mtch_stop_ce;
if (payload) {
nof_mch_sched_ce = nof_bytes / 2;
if (cur_mch_sched_ce < nof_mch_sched_ce) {
*lcid_ = (payload[cur_mch_sched_ce * 2] & 0xF8) >> 3;
mtch_stop_ce = ((uint16_t)(payload[cur_mch_sched_ce * 2] & 0x07)) << 8;
mtch_stop_ce += payload[cur_mch_sched_ce * 2 + 1];
cur_mch_sched_ce++;
*mtch_stop = (mtch_stop_ce == sch_subh::MTCH_STOP_EMPTY) ? (0) : (mtch_stop_ce);
return true;
}
nof_mch_sched_ce = nof_bytes / 2;
if (cur_mch_sched_ce < nof_mch_sched_ce) {
*lcid_ = (payload[cur_mch_sched_ce * 2] & 0xF8) >> 3;
mtch_stop_ce = ((uint16_t)(payload[cur_mch_sched_ce * 2] & 0x07)) << 8;
mtch_stop_ce += payload[cur_mch_sched_ce * 2 + 1];
cur_mch_sched_ce++;
*mtch_stop = (mtch_stop_ce == sch_subh::MTCH_STOP_EMPTY) ? (0) : (mtch_stop_ce);
return true;
}
return false;
}
uint8_t sch_subh::get_ta_cmd()
{
if (payload) {
return (uint8_t)payload[0] & 0x3f;
} else {
return 0;
}
return (uint8_t)payload[0] & 0x3f;
}
uint8_t sch_subh::get_activation_deactivation_cmd()
{
/* 3GPP 36.321 section 6.1.3.8 Activation/Deactivation MAC Control Element */
if (payload) {
return payload[0];
} else {
return 0;
}
return payload[0];
}
uint32_t sch_subh::get_sdu_lcid()
@ -677,7 +652,8 @@ void sch_subh::set_padding()
set_padding(0);
}
bool sch_subh::set_bsr(uint32_t buff_size[4], ul_sch_lcid format)
// Update the BSR content without changing the type
void sch_subh::update_bsr(uint32_t buff_size[4], ul_sch_lcid format)
{
uint32_t nonzero_lcg = 0;
for (int i = 0; i < 4; i++) {
@ -685,15 +661,25 @@ bool sch_subh::set_bsr(uint32_t buff_size[4], ul_sch_lcid format)
nonzero_lcg = i;
}
}
if (format == ul_sch_lcid::LONG_BSR) {
w_payload_ce[0] = ((buff_size_table(buff_size[0]) & 0x3f) << 2) | ((buff_size_table(buff_size[1]) & 0x30) >> 4);
w_payload_ce[1] = ((buff_size_table(buff_size[1]) & 0xf) << 4) | ((buff_size_table(buff_size[2]) & 0x3c) >> 2);
w_payload_ce[2] = ((buff_size_table(buff_size[2]) & 0x3) << 6) | ((buff_size_table(buff_size[3]) & 0x3f));
} else {
w_payload_ce[0] = (nonzero_lcg & 0x3) << 6 | (buff_size_table(buff_size[nonzero_lcg]) & 0x3f);
}
}
// Makes a MAC PDU sub header a BSR subheader
// It checks that enough space is left in the MAC PDU and
// updates the remaning length of the parent MAC PDU
// @return true if given BSR format could be set, false otherwise
bool sch_subh::set_bsr(uint32_t buff_size[4], ul_sch_lcid format)
{
uint32_t ce_size = format == ul_sch_lcid::LONG_BSR ? 3 : 1;
if (((sch_pdu*)parent)->has_space_ce(ce_size)) {
if (format == ul_sch_lcid::LONG_BSR) {
w_payload_ce[0] = ((buff_size_table(buff_size[0]) & 0x3f) << 2) | ((buff_size_table(buff_size[1]) & 0x30) >> 4);
w_payload_ce[1] = ((buff_size_table(buff_size[1]) & 0xf) << 4) | ((buff_size_table(buff_size[2]) & 0x3c) >> 2);
w_payload_ce[2] = ((buff_size_table(buff_size[2]) & 0x3) << 6) | ((buff_size_table(buff_size[3]) & 0x3f));
} else {
w_payload_ce[0] = (nonzero_lcg & 0x3) << 6 | (buff_size_table(buff_size[nonzero_lcg]) & 0x3f);
}
update_bsr(buff_size, format);
lcid = (uint32_t)format;
((sch_pdu*)parent)->update_space_ce(ce_size);
nof_bytes = ce_size;
@ -904,30 +890,39 @@ void sch_subh::read_payload(uint8_t** ptr)
*ptr += nof_bytes;
}
void sch_subh::fprint(FILE* stream)
std::string sch_subh::to_string()
{
std::stringstream ss;
if (is_sdu()) {
fprintf(stream, "SDU LCHID=%d, SDU nof_bytes=%d\n", lcid, nof_bytes);
ss << "LCID=" << lcid << " len=" << nof_bytes;
} else if (type == SCH_SUBH_TYPE) {
if (parent->is_ul()) {
switch ((ul_sch_lcid)lcid) {
case ul_sch_lcid::CRNTI:
fprintf(stream, "C-RNTI CE\n");
ss << "CRNTI:";
break;
case ul_sch_lcid::PHR_REPORT:
fprintf(stream, "PHR\n");
ss << "PHR: ph=" << get_phr();
break;
case ul_sch_lcid::TRUNC_BSR:
fprintf(stream, "Truncated BSR CE\n");
break;
case ul_sch_lcid::SHORT_BSR:
fprintf(stream, "Short BSR CE\n");
break;
case ul_sch_lcid::LONG_BSR:
fprintf(stream, "Long BSR CE\n");
break;
case ul_sch_lcid::LONG_BSR: {
uint32_t buff_size_idx[4] = {};
uint32_t buff_size_bytes[4] = {};
uint32_t lcg = get_bsr(buff_size_idx, buff_size_bytes);
if (ul_sch_ce_type() == ul_sch_lcid::LONG_BSR) {
ss << "LBSR: b=";
for (uint32_t i = 0; i < 4; i++) {
ss << buff_size_idx[i] << " ";
}
} else if (ul_sch_ce_type() == ul_sch_lcid::SHORT_BSR) {
ss << "SBSR: lcg=" << lcg << " b=" << buff_size_idx[lcg];
} else {
ss << "TBSR: lcg=" << lcg << " b=" << buff_size_idx[lcg];
}
} break;
case ul_sch_lcid::PADDING:
fprintf(stream, "PADDING\n");
ss << "PAD: len=" << get_payload_size();
break;
default:
// do nothing
@ -936,16 +931,16 @@ void sch_subh::fprint(FILE* stream)
} else {
switch ((dl_sch_lcid)lcid) {
case dl_sch_lcid::CON_RES_ID:
fprintf(stream, "Contention Resolution ID CE: 0x%" PRIx64 "\n", get_con_res_id());
ss << "CON_RES: id=" << get_con_res_id();
break;
case dl_sch_lcid::TA_CMD:
fprintf(stream, "Time Advance Command CE: %d\n", get_ta_cmd());
ss << "TA: ta=" << get_ta_cmd();
break;
case dl_sch_lcid::DRX_CMD:
fprintf(stream, "DRX Command CE: Not implemented\n");
ss << "DRX";
break;
case dl_sch_lcid::PADDING:
fprintf(stream, "PADDING\n");
ss << "PAD: len=" << get_payload_size();
break;
default:
break;
@ -954,15 +949,16 @@ void sch_subh::fprint(FILE* stream)
} else if (type == MCH_SUBH_TYPE) {
switch ((mch_lcid)lcid) {
case mch_lcid::MCH_SCHED_INFO:
fprintf(stream, "MCH Scheduling Info CE\n");
ss << "MCH_SCHED_INFO";
break;
case mch_lcid::PADDING:
fprintf(stream, "PADDING\n");
ss << "PAD: len=" << get_payload_size();
break;
default:
break;
}
}
return ss.str();
}
uint8_t sch_subh::buff_size_table(uint32_t buffer_size)
@ -993,10 +989,11 @@ uint8_t sch_subh::phr_report_table(float phr_value)
return (uint8_t)floor(phr_value + 23);
}
void rar_pdu::fprint(FILE* stream)
std::string rar_pdu::to_string()
{
fprintf(stream, "MAC PDU for RAR. ");
pdu::fprint(stream);
std::string msg("MAC PDU for RAR. ");
msg += pdu::to_string();
return msg;
}
rar_pdu::rar_pdu(uint32_t max_rars_, srslte::log_ref log_) : pdu(max_rars_, log_)
@ -1050,15 +1047,20 @@ bool rar_pdu::write_packet(uint8_t* ptr)
return true;
}
void rar_subh::fprint(FILE* stream)
std::string rar_subh::to_string()
{
std::stringstream ss;
if (type == RAPID) {
fprintf(stream, "RAPID: %d, Temp C-RNTI: %d, TA: %d, UL Grant: ", preamble, temp_rnti, ta);
ss << "RAPID: " << preamble << ", Temp C-RNTI: " << temp_rnti << ", TA: " << ta << ", UL Grant: ";
} else {
fprintf(stream, "Backoff Indicator %d. ", ((rar_pdu*)parent)->get_backoff());
ss << "Backoff Indicator: " << int32_t(((rar_pdu*)parent)->get_backoff()) << " ";
}
srslte_vec_fprint_hex(stream, grant, 20);
char tmp[16];
srslte_vec_sprint_hex(tmp, sizeof(tmp), grant, RAR_GRANT_LEN);
ss << tmp << "\n";
return ss.str();
}
void rar_subh::init()

View File

@ -59,7 +59,7 @@ int mac_rar_pdu_unpack_test1()
srslte::rar_pdu rar_pdu_msg;
rar_pdu_msg.init_rx(sizeof(rar_pdu_tv1));
rar_pdu_msg.parse_packet(rar_pdu_tv1);
rar_pdu_msg.fprint(stdout);
std::cout << rar_pdu_msg.to_string() << std::endl;
TESTASSERT(not rar_pdu_msg.has_backoff());
while (rar_pdu_msg.next()) {
@ -76,7 +76,7 @@ int mac_rar_pdu_unpack_test2()
srslte::rar_pdu rar_pdu_msg;
rar_pdu_msg.init_rx(sizeof(rar_pdu_tv2));
rar_pdu_msg.parse_packet(rar_pdu_tv2);
rar_pdu_msg.fprint(stdout);
std::cout << rar_pdu_msg.to_string() << std::endl;
TESTASSERT(rar_pdu_msg.has_backoff());
TESTASSERT(rar_pdu_msg.get_backoff() == BACKOFF_IND_TV2);