From db56a3563e3d76f75613581b666390c4ceddbc3d Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Sat, 22 Aug 2020 02:05:28 +0700 Subject: [PATCH] encoding: use CSN.1 codec to generate Packet Uplink Assignment It's quite odd to see that in write_packet_downlink_assignment() we initialize an 'RlcMacDownlink_t', so then the caller can use the power of CSN.1 codec to generate the final sequence of bytes to be transmitted, while in write_packet_uplink_assignment() we already compose the final RLC/MAC message straight away using the low-level bitvec API (like bitvec_write_field()). I guess the reason is that at the time of writing this code, the CSN.1 codec was not stable enough, so it was safer to generate the message 'by hand'. This would also explain why we *decode* the final RLC/MAC message in create_ul_ass() right after encoding. Rewrite write_packet_uplink_assignment(), so now it initializes a caller-provided 'RlcMacDownlink_t' structure. Given that it's allocated on heap using talloc_zero(), do not initialize presence indicators of fields that are not present in the message. This would facilitate handling of frequency hopping parameters in the upcoming changes, in particular we can now introduce a function that would compose Frequency Parameters IE for both write_packet_{downlink,uplink}_assignment(). Tested manually by running a GPRS-enabled network, as well as by running test cases from ttcn3-pcu-test => no regressions observed. Change-Id: I2850b91e0043cdca8ae7498a5fc727eeedd029b6 Related: SYS#4868, OS#4547 --- src/encoding.cpp | 176 +++++++++++++++++++++++++++-------------------- src/encoding.h | 2 +- src/tbf.cpp | 8 +-- 3 files changed, 108 insertions(+), 78 deletions(-) diff --git a/src/encoding.cpp b/src/encoding.cpp index 2cee2516..ef21b61a 100644 --- a/src/encoding.cpp +++ b/src/encoding.cpp @@ -536,95 +536,125 @@ int Encoding::write_immediate_assignment( return plen; } -/* generate uplink assignment */ +/* Generate Packet Uplink Assignment as per 3GPP TS 44.060, section 11.2.29. + * NOTE: 'block' is expected to be zero-initialized by the caller. */ void Encoding::write_packet_uplink_assignment( - bitvec * dest, uint8_t old_tfi, + RlcMacDownlink_t * block, uint8_t old_tfi, uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, const struct gprs_rlcmac_ul_tbf *tbf, uint8_t poll, uint8_t rrbp, uint8_t alpha, uint8_t gamma, int8_t ta_idx, bool use_egprs) { - // TODO We should use our implementation of encode RLC/MAC Control messages. - unsigned wp = 0; - uint8_t ts; - /* timeslot assigned for the Continuous Timing Advance procedure */ - uint8_t ta_ts = 0; /* FIXME: supply it as parameter from caller */ + Packet_Uplink_Assignment_t *pua; + Packet_Timing_Advance_t *pta; + Frequency_Parameters_t *fp; + Dynamic_Allocation_t *da; - bitvec_write_field(dest, &wp,0x1,2); // Payload Type - bitvec_write_field(dest, &wp,rrbp,2); // Uplink block with TDMA framenumber (N+13) - bitvec_write_field(dest, &wp,poll,1); // Suppl/Polling Bit - bitvec_write_field(dest, &wp,0x0,3); // Uplink state flag - bitvec_write_field(dest, &wp,0xa,6); // MESSAGE TYPE + /* RLC/MAC control block without the optional RLC/MAC control header */ + block->PAYLOAD_TYPE = 0x01; // Payload Type + block->RRBP = rrbp; // RRBP (e.g. N+13) + block->SP = poll; // RRBP field is valid + block->USF = 0x00; // Uplink state flag - bitvec_write_field(dest, &wp,0x0,2); // Page Mode + /* See 3GPP TS 44.060, section 11.2.29 */ + pua = &block->u.Packet_Uplink_Assignment; + pua->MESSAGE_TYPE = 0x0a; // Packet Uplink Assignment + pua->PAGE_MODE = 0x00; // Normal Paging - bitvec_write_field(dest, &wp,0x0,1); // switch PERSIST_LEVEL: off + /* TLLI or Global (UL/DL) TFI */ if (use_tlli) { - bitvec_write_field(dest, &wp,0x2,2); // switch TLLI : on - bitvec_write_field(dest, &wp,tlli,32); // TLLI + pua->ID.UnionType = 0x01; + pua->ID.u.TLLI = tlli; } else { - bitvec_write_field(dest, &wp,0x0,1); // switch TFI : on - bitvec_write_field(dest, &wp,old_downlink,1); // 0=UPLINK TFI, 1=DL TFI - bitvec_write_field(dest, &wp,old_tfi,5); // TFI + pua->ID.UnionType = 0x00; + pua->ID.u.Global_TFI.UnionType = old_downlink; + pua->ID.u.Global_TFI.u.UPLINK_TFI = old_tfi; } + /* GPRS/EGPRS specific parameters */ + pua->UnionType = use_egprs ? 0x01 : 0x00; if (!use_egprs) { - bitvec_write_field(dest, &wp,0x0,1); // Message escape - bitvec_write_field(dest, &wp, mcs_chan_code(tbf->current_cs()), 2); // CHANNEL_CODING_COMMAND - bitvec_write_field(dest, &wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING - write_ta_ie(dest, wp, tbf->ta(), ta_idx, ta_ts); - } else { /* EPGRS */ - bitvec_write_field(dest, &wp,0x1,1); // Message escape - bitvec_write_field(dest, &wp,0x0,2); // EGPRS message contents - bitvec_write_field(dest, &wp,0x0,1); // No CONTENTION_RESOLUTION_TLLI - bitvec_write_field(dest, &wp,0x0,1); // No COMPACT reduced MA - bitvec_write_field(dest, &wp, mcs_chan_code(tbf->current_cs()), 4); // EGPRS Modulation and Coding IE - /* 0: no RESEGMENT, 1: Segmentation*/ - bitvec_write_field(dest, &wp, 0x1, 1); - write_ws(dest, &wp, tbf->window_size()); // EGPRS Window Size - bitvec_write_field(dest, &wp,0x0,1); // No Access Technologies Request - bitvec_write_field(dest, &wp,0x0,1); // No ARAC RETRANSMISSION REQUEST - bitvec_write_field(dest, &wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING - bitvec_write_field(dest, &wp,0x0,1); // No BEP_PERIOD2 - write_ta_ie(dest, wp, tbf->ta(), ta_idx, ta_ts); - bitvec_write_field(dest, &wp,0x0,1); // No Packet Extended Timing Advance + PUA_GPRS_t *gprs = &pua->u.PUA_GPRS_Struct; + + /* Use the commanded CS/MSC value during the content resolution */ + gprs->CHANNEL_CODING_COMMAND = mcs_chan_code(tbf->current_cs()); + gprs->TLLI_BLOCK_CHANNEL_CODING = 0x01; // ^^^ + + /* Dynamic allocation */ + gprs->UnionType = 0x01; + /* Frequency Parameters IE is present */ + gprs->Exist_Frequency_Parameters = 0x01; + + /* Common parameters to be set below */ + pta = &gprs->Packet_Timing_Advance; + fp = &gprs->Frequency_Parameters; + da = &gprs->u.Dynamic_Allocation; + } else { + PUA_EGPRS_00_t *egprs = &pua->u.PUA_EGPRS_Struct.u.PUA_EGPRS_00; + pua->u.PUA_EGPRS_Struct.UnionType = 0x00; // 'Normal' EGPRS, not EGPRS2 + + /* Use the commanded CS/MSC value during the content resolution */ + egprs->EGPRS_CHANNEL_CODING_COMMAND = mcs_chan_code(tbf->current_cs()); + egprs->TLLI_BLOCK_CHANNEL_CODING = 0x01; // ^^^ + egprs->RESEGMENT = 0x01; // Enable segmentation + egprs->EGPRS_WindowSize = tbf->window_size(); + + /* Dynamic allocation */ + egprs->UnionType = 0x01; + /* Frequency Parameters IE is present */ + egprs->Exist_Frequency_Parameters = 0x01; + + /* Common parameters to be set below */ + pta = &egprs->Packet_Timing_Advance; + fp = &egprs->Frequency_Parameters; + da = &egprs->u.Dynamic_Allocation; } -#if 1 - bitvec_write_field(dest, &wp,0x1,1); // Frequency Parameters information elements = present - bitvec_write_field(dest, &wp,tbf->tsc(),3); // Training Sequence Code (TSC) - bitvec_write_field(dest, &wp,0x0,2); // ARFCN = present - bitvec_write_field(dest, &wp,tbf->trx->arfcn,10); // ARFCN -#else - bitvec_write_field(dest, &wp,0x0,1); // Frequency Parameters = off -#endif - - bitvec_write_field(dest, &wp,0x1,2); // Dynamic Allocation - - bitvec_write_field(dest, &wp,0x0,1); // Extended Dynamic Allocation = off - bitvec_write_field(dest, &wp,0x0,1); // P0 = off - - bitvec_write_field(dest, &wp,0x0,1); // USF_GRANULARITY - bitvec_write_field(dest, &wp,0x1,1); // switch TFI : on - bitvec_write_field(dest, &wp,tbf->tfi(),5);// TFI - - bitvec_write_field(dest, &wp,0x0,1); // - bitvec_write_field(dest, &wp,0x0,1); // TBF Starting Time = off - if (alpha || gamma) { - bitvec_write_field(dest, &wp,0x1,1); // Timeslot Allocation with Power Control - bitvec_write_field(dest, &wp,alpha,4); // ALPHA - } else - bitvec_write_field(dest, &wp,0x0,1); // Timeslot Allocation - - for (ts = 0; ts < 8; ts++) { - if (tbf->pdch[ts]) { - bitvec_write_field(dest, &wp,0x1,1); // USF_TN(i): on - bitvec_write_field(dest, &wp,tbf->m_usf[ts],3); // USF_TN(i) - if (alpha || gamma) - bitvec_write_field(dest, &wp,gamma,5); // GAMMA power control parameter - } else - bitvec_write_field(dest, &wp,0x0,1); // USF_TN(i): off + /* Packet Timing Advance (if known) */ + if (tbf->ta() <= 63) { /* { 0 | 1 < TIMING_ADVANCE_VALUE : bit (6) > } */ + pta->Exist_TIMING_ADVANCE_VALUE = 0x01; // Present + pta->TIMING_ADVANCE_VALUE = tbf->ta(); + } + + /* Continuous Timing Advance Control */ + if (ta_idx >= 0 && ta_idx < 16) { + pta->Exist_IndexAndtimeSlot = 0x01; // Present + pta->TIMING_ADVANCE_TIMESLOT_NUMBER = 0; // FIXME! + pta->TIMING_ADVANCE_INDEX = ta_idx; + } + + /* Frequency Parameters IE */ + fp->TSC = tbf->tsc(); // Training Sequence Code (TSC) + fp->UnionType = 0x00; // Single ARFCN + fp->u.ARFCN = tbf->trx->arfcn; + + /* Dynamic allocation parameters */ + da->USF_GRANULARITY = 0x00; + + /* Assign an Uplink TFI */ + da->Exist_UPLINK_TFI_ASSIGNMENT = 0x01; + da->UPLINK_TFI_ASSIGNMENT = tbf->tfi(); + + /* Timeslot Allocation with or without Power Control */ + da->UnionType = (alpha || gamma) ? 0x01 : 0x00; + if (da->UnionType == 0x01) + da->u.Timeslot_Allocation_Power_Ctrl_Param.ALPHA = alpha; + + for (unsigned int tn = 0; tn < 8; tn++) { + if (tbf->pdch[tn] == NULL) + continue; + + if (da->UnionType == 0x01) { + Timeslot_Allocation_Power_Ctrl_Param_t *params = \ + &da->u.Timeslot_Allocation_Power_Ctrl_Param; + params->Slot[tn].Exist = 0x01; // Enable this timeslot + params->Slot[tn].USF_TN = tbf->m_usf[tn]; // USF_TN(i) + params->Slot[tn].GAMMA_TN = gamma; + } else { + Timeslot_Allocation_t *slot = &da->u.Timeslot_Allocation[tn]; + slot->Exist = 0x01; // Enable this timeslot + slot->USF_TN = tbf->m_usf[tn]; // USF_TN(i) + } } - // bitvec_write_field(dest, &wp,0x0,1); // Measurement Mapping struct not present } diff --git a/src/encoding.h b/src/encoding.h index 18392f75..5f8496eb 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -58,7 +58,7 @@ public: ); static void write_packet_uplink_assignment( - bitvec * dest, uint8_t old_tfi, + RlcMacDownlink_t * block, uint8_t old_tfi, uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, const struct gprs_rlcmac_ul_tbf *tbf, uint8_t poll, uint8_t rrbp, uint8_t alpha, uint8_t gamma, int8_t ta_idx, diff --git a/src/tbf.cpp b/src/tbf.cpp index c1ec7291..0447edc2 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -1368,16 +1368,16 @@ struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn, uint8_t ts) bitvec_unhex(&bv, DUMMY_VEC); LOGPTBF(new_tbf, LOGL_INFO, "start Packet Uplink Assignment (PACCH)\n"); - Encoding::write_packet_uplink_assignment(&bv, m_tfi, + mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); + Encoding::write_packet_uplink_assignment(mac_control_block, m_tfi, (direction == GPRS_RLCMAC_DL_TBF), tlli(), is_tlli_valid(), new_tbf, 1, rrbp, bts_data()->alpha, bts_data()->gamma, -1, is_egprs_enabled()); - mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); LOGP(DTBF, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n"); - rc = decode_gsm_rlcmac_downlink(&bv, mac_control_block); + rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block); if (rc < 0) { - LOGP(DTBF, LOGL_ERROR, "Decoding of Packet Uplink Ass failed (%d)\n", rc); + LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Uplink Ass failed (%d)\n", rc); goto free_ret; } LOGP(DTBF, LOGL_DEBUG, "------------------------- TX : Packet Uplink Assignment -------------------------\n");