osmo-pcu/src/rlc.cpp

809 lines
23 KiB
C++

/*
* Copyright (C) 2013 by Holger Hans Peter Freyther
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "tbf.h"
#include "bts.h"
#include "gprs_debug.h"
extern "C" {
#include <osmocom/core/utils.h>
}
const uint8_t* one_run_len_code_list[MAX_CDWDTBL_LEN] = {
(uint8_t*)"00110101", (uint8_t*)"000111", (uint8_t*)"0111", (uint8_t*)"1000",
(uint8_t*) "1011", (uint8_t*)"1100", (uint8_t*)"1110", (uint8_t*)"1111",
(uint8_t*)"10011", (uint8_t*)"10100", (uint8_t*)"00111", (uint8_t*)"01000",
(uint8_t*)"001000", (uint8_t*)"000011", (uint8_t*)"110100", (uint8_t*)"110101",
(uint8_t*)"101010", (uint8_t*)"101011", (uint8_t*)"0100111", (uint8_t*)"0001100",
(uint8_t*)"0001000", (uint8_t*)"0010111", (uint8_t*)"0000011", (uint8_t*)"0000100",
(uint8_t*)"0101000", (uint8_t*)"0101011", (uint8_t*)"0010011", (uint8_t*)"0100100",
(uint8_t*)"0011000", (uint8_t*)"00000010", (uint8_t*)"00000011", (uint8_t*)"00011010",
(uint8_t*)"00011011", (uint8_t*)"00010010", (uint8_t*)"00010011", (uint8_t*)"00010100",
(uint8_t*)"00010101", (uint8_t*)"00010110", (uint8_t*)"00010111", (uint8_t*)"00101000",
(uint8_t*)"00101001", (uint8_t*)"00101010", (uint8_t*)"00101011", (uint8_t*)"00101100",
(uint8_t*)"00101101", (uint8_t*)"00000100", (uint8_t*)"00000101", (uint8_t*)"00001010",
(uint8_t*)"00001011", (uint8_t*)"01010010", (uint8_t*)"01010011", (uint8_t*)"01010100",
(uint8_t*)"01010101", (uint8_t*)"00100100", (uint8_t*)"00100101", (uint8_t*)"01011000",
(uint8_t*)"01011001", (uint8_t*)"01011010", (uint8_t*)"01011011", (uint8_t*)"01001010",
(uint8_t*)"01001011", (uint8_t*)"00110010", (uint8_t*)"00110011", (uint8_t*)"00110100",
(uint8_t*)"11011", (uint8_t*)"10010", (uint8_t*)"010111", (uint8_t*)"0110111",
(uint8_t*)"00110110", (uint8_t*)"00110111", (uint8_t*)"01100100", (uint8_t*)"01100101",
(uint8_t*)"01101000", (uint8_t*)"01100111", (uint8_t*)"011001100",(uint8_t*)"011001101",
(uint8_t*)"011010010", (uint8_t*)"011010011",(uint8_t*)"011010100"
};
const uint8_t* zero_run_len_code_list[MAX_CDWDTBL_LEN] = {
(uint8_t*)"0000110111", (uint8_t*)"10", (uint8_t*)"11", (uint8_t*)"010",
(uint8_t*)"011", (uint8_t*)"0011", (uint8_t*)"0010", (uint8_t*)"00011",
(uint8_t*)"000101", (uint8_t*)"000100", (uint8_t*)"0000100", (uint8_t*)"0000101",
(uint8_t*)"0000111", (uint8_t*)"00000100", (uint8_t*)"00000111", (uint8_t*)"000011000",
(uint8_t*)"0000010111", (uint8_t*)"0000011000", (uint8_t*)"0000001000", (uint8_t*)"00001100111",
(uint8_t*)"00001101000", (uint8_t*)"00001101100", (uint8_t*)"00000110111", (uint8_t*)"00000101000",
(uint8_t*)"00000010111", (uint8_t*)"00000011000", (uint8_t*)"000011001010",(uint8_t*)"000011001011",
(uint8_t*)"000011001100",(uint8_t*)"000011001101",(uint8_t*)"000001101000",(uint8_t*)"000001101001",
(uint8_t*)"000001101010",(uint8_t*)"000001101011",(uint8_t*)"000011010010",(uint8_t*)"000011010011",
(uint8_t*)"000011010100",(uint8_t*)"000011010101",(uint8_t*)"000011010110",(uint8_t*)"000011010111",
(uint8_t*)"000001101100",(uint8_t*)"000001101101",(uint8_t*)"000011011010",(uint8_t*)"000011011011",
(uint8_t*)"000001010100",(uint8_t*)"000001010101",(uint8_t*)"000001010110",(uint8_t*)"000001010111",
(uint8_t*)"000001100100",(uint8_t*)"000001100101",(uint8_t*)"000001010010",(uint8_t*)"000001010011",
(uint8_t*)"000000100100",(uint8_t*)"000000110111",(uint8_t*)"000000111000",(uint8_t*)"000000100111",
(uint8_t*)"000000101000",(uint8_t*)"000001011000",(uint8_t*)"000001011001",(uint8_t*)"000000101011",
(uint8_t*)"000000101100",(uint8_t*)"000001011010",(uint8_t*)"000001100110",(uint8_t*)"000001100111",
(uint8_t*)"0000001111", (uint8_t*)"000011001000",(uint8_t*)"000011001001",(uint8_t*)"000001011011",
(uint8_t*)"000000110011",(uint8_t*)"000000110100",(uint8_t*)"000000110101",(uint8_t*)"0000001101100",
(uint8_t*)"0000001101101",(uint8_t*)"0000001001010", (uint8_t*)"0000001001011",
(uint8_t*)"0000001001100", (uint8_t*)"0000001001101", (uint8_t*)"0000001110010",
(uint8_t*)"0000001110011"
};
/*
*
*
* Desc: This function rebuilds a header from Type II to Type III
* the source is header2 and the new header is put
* into the enc structure
*
*/
int gprs_rlc_data::egprs_build_header_type3_from_type2
(
uint8_t *enc, /* header to unpack */
GprsCodingScheme *reseg_mcs, /* resegmentation MCS */
uint8_t ps,
uint8_t spb /* SPB field */
)
{
uint8_t byte;
/* Type 3 and type 2 are differed with only last byte to include spb offset */
memcpy(enc, this->hdr_ptr[0], EGPRS_TYPE3_HDR_SIZE);
struct gprs_rlc_dl_header_egprs_3 *header_type3 = (struct gprs_rlc_dl_header_egprs_3 *)enc;
byte = reseg_mcs->get_cps(ps, this->mcs8_retx);
header_type3->cps = byte;
header_type3->spb = spb;
return(1);
} /* end of egprs_build_header_type3_from_type2*/
/*
*
* Fun: egprs_build_header_type3_from_type1
*
* Desc: This function rebuilds a header from Type I to Type III
* the source is header1 and the new header is put
* into the enc structure
* This function is needed for resegmentation from MCS7/8/9 to
* MCS 2/3
*
* Ret: 1 if successful or,
* -1, otherwise
*
* Notes: None
*
* File: gz_egprs1.c
*
*/
int gprs_rlc_data::egprs_build_header_type3_from_type1
(
uint8_t *enc, /* header to unpack */
GprsCodingScheme *reseg_mcs, /* resegmentation MCS */
uint8_t ps,
uint8_t spb/* SPB field */
)
{
uint8_t byte;
struct gprs_rlc_dl_header_egprs_3 *header_type3 = (struct gprs_rlc_dl_header_egprs_3 *) enc;
memcpy(enc, this->hdr_ptr[0], EGPRS_TYPE3_HDR_SIZE);
/* depending on wether if it is the first or the second
block of the original MCS-7/8/9 block we choose the BSN
*/
header_type3->bsn_a = (this->bsn & 0x3);
header_type3->bsn_b = this->bsn >> 2 ;
header_type3->bsn_c = this->bsn & 0x0400 ;
byte = reseg_mcs->get_cps(ps, this->mcs8_retx);
header_type3->cps = byte;
header_type3->spb = spb;
return(1);
} /* end of egprs_build_header_type3_from_type1 */
/*
*
* Desc: This function rebuilds a header from Type I to Type II
* the source is header1 and the new header is put
* into the enc structure
* In this case 2 headers are returned since the BSN for
* each resegmented block is different
*/
int gprs_rlc_data::egprs_build_header_type2_from_type1
(
uint8_t *enc, /* header to unpack */
GprsCodingScheme *reseg_mcs, /* resegmentation MCS */
uint8_t ps
)
{
uint8_t byte;
struct gprs_rlc_dl_header_egprs_2 *header_type2 = (struct gprs_rlc_dl_header_egprs_2 *) enc;
memcpy(enc, this->hdr_ptr[0], EGPRS_TYPE2_HDR_SIZE);
/* depending on wether if it is the first or the second
block of the original MCS-7/8/9 block we choose the BSN
*/
header_type2->bsn_a = (this->bsn & 0x3);
header_type2->bsn_b = this->bsn >> 2 ;
header_type2->bsn_c = this->bsn & 0x0400 ;
byte = reseg_mcs->get_cps(ps, this->mcs8_retx);
header_type2->cps = byte;
return(1);
} /* end of egprs_build_header_type2_from_type1*/
void gprs_rlc_data::update_cps( GprsCodingScheme *cs, const uint8_t next_ps)
{
uint8_t cps = cs->get_cps(next_ps, false);
if((*cs == GprsCodingScheme::MCS1 ||
*cs == GprsCodingScheme::MCS2 ||
*cs == GprsCodingScheme::MCS3 ||
*cs == GprsCodingScheme::MCS4)){
this->last_ps = next_ps;
this->hdr_ptr[0][3] |= cps << 1 ;
}
else if( (*cs == GprsCodingScheme::MCS5) ||
(*cs == GprsCodingScheme::MCS6)){
this->last_ps = next_ps;
this->hdr_ptr[0][3] |= cps << 1 ;
}else if((*cs == GprsCodingScheme::MCS7) ||
(*cs == GprsCodingScheme::MCS8) ||
( *cs == GprsCodingScheme::MCS9)){
this->last_ps = next_ps;
this->hdr_ptr[0][4] = cps<< 3 ;
}
else{
OSMO_ASSERT(*cs >= GprsCodingScheme::MCS9);
}
}
void gprs_rlc_data::fill_hdr_type3( GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi,const uint16_t cps)
{
/*Refer Header type from 10.3a.3.3 of 46.060*/
struct gprs_rlc_dl_header_egprs_3 *ptr = (struct gprs_rlc_dl_header_egprs_3 *)hdr_ptr[0];
ptr->usf = GPRS_RLCMAC_DATA_BLOCK;
ptr->tfi_a = tfi & 0x01;
ptr->tfi_b = tfi >> 1;
ptr->bsn_a = bsn & 0x3;
ptr->bsn_b = bsn >> 2 ;
ptr->bsn_c = bsn & 0x0400 ;
/* Need to check with cs */
ptr->cps = cps;
ptr->spb = 0;
LOGP(DRLCMACDL, LOGL_DEBUG, "usf=%d\n tfi_a=%d\n tfi_b=%d\n bsna %d \n bsnb %d\n bsnc %d\n cps %d\n spb %d\n",
ptr->usf, ptr->tfi_a, ptr->tfi_b, ptr->bsn_a,ptr->bsn_b,ptr->bsn_c,ptr->cps,ptr->spb);
this->cs = *cs;
this->hdr_size[0] = EGPRS_TYPE3_HDR_SIZE;
}
void gprs_rlc_data::fill_hdr_type2( GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi,const uint16_t cps )
{
/*Refer Header type from 10.3a.3.2 of 46.060*/
struct gprs_rlc_dl_header_egprs_2 *ptr = (struct gprs_rlc_dl_header_egprs_2 *)hdr_ptr[0];
ptr->usf = GPRS_RLCMAC_DATA_BLOCK;
ptr->tfi_a = tfi & 0x01;
ptr->tfi_b = tfi >> 1;
ptr->bsn_a = bsn & 0x3;
ptr->bsn_b = bsn >> 2 ;
ptr->bsn_c = bsn & 0x0400 ;
/* Need to check with cs */
ptr->cps = cps;
LOGP(DRLCMACDL, LOGL_DEBUG, "usf=%d\n tfi_a=%d\n tfi_b=%d\n bsna %d \n bsnb %d\n bsnc %d\n cps %d\n",
ptr->usf, ptr->tfi_a, ptr->tfi_b, ptr->bsn_a,ptr->bsn_b,ptr->bsn_c,ptr->cps);
this->cs = *cs;
this->hdr_size[0] = EGPRS_TYPE2_HDR_SIZE;
}
void gprs_rlc_data::set_resend_fn_ts(const uint32_t fn, const uint8_t ts)
{
this->resend_fn = fn;
this->resend_ts = ts;
}
void gprs_rlc_data::fill_hdr_type1(GprsCodingScheme *cs, const uint16_t bsn, const uint16_t tfi , const uint16_t cps)
{
/*Refer Header type from 10.3a.3.1 of 46.060*/
struct gprs_rlc_dl_header_egprs_1 *ptr = (struct gprs_rlc_dl_header_egprs_1 *)hdr_ptr[0];
ptr->usf = GPRS_RLCMAC_DATA_BLOCK;
ptr->tfi_a = tfi & 0x01;
ptr->tfi_b = tfi >> 1;
ptr->bsn1_a = bsn & 0x3;
ptr->bsn1_b = bsn >> 2 ;
ptr->bsn1_c = bsn & 0x0400 ;
/*
Theres no scope of retx and Tx block clubbing present in our design
hence bsn2 is always assumed to be 1 i.e bsn2 = nextbsn(bsn1) = 1
*/
ptr->bsn2_a = 1;
ptr->bsn2_b = 0 ;
ptr->cps = cps;
this->cs = *cs;
LOGP(DRLCMACDL, LOGL_DEBUG, "usf :%d \n es :%d\n rrbp: %d \n tfi1:%d\n tfi2:%d\n bsn1a%d \n bsn1b %d \n bsn1c%d\n"
"bsn2a %d\n bsn2b %d\n ",ptr ->usf, ptr -> es_p, ptr -> rrbp, ptr -> tfi_a, ptr ->tfi_b, ptr->bsn1_a,
ptr->bsn1_b, ptr->bsn1_c, ptr->bsn2_a, ptr->bsn2_b);
LOGP(DRLCMACDL, LOGL_DEBUG, "pr: %d cps:%d ", ptr -> pr, ptr ->cps);
this->hdr_size[0] = EGPRS_TYPE1_HDR_SIZE;
}
uint8_t *gprs_rlc_data::prepare(size_t block_data_len)
{
/* todo.. only set it once if it turns out to be a bottleneck */
memset(complete_blk, 0x0, sizeof(complete_blk));
memset(complete_blk, 0x2b, block_data_len);
memset(&hdr_ptr[0],0, RLC_MAX_HDR_SIZE);
memset(&hdr_ptr[1],0, RLC_MAX_HDR_SIZE);
this->mcs8_retx = false;
this->reseg_status = EGPRS_RESEG_SINGLE_BLOCK;
this->len_block2 = 0;
return complete_blk;
}
void gprs_rlc_data::put_data(const uint8_t *data, size_t data_len)
{
memcpy(complete_blk, data, data_len);
completed_block_len = data_len;
}
void gprs_rlc_v_b::reset()
{
for (size_t i = 0; i < ARRAY_SIZE(m_v_b); ++i)
mark_invalid(i);
}
void gprs_rlc_dl_window::reset()
{
m_v_s = 0;
m_v_a = 0;
m_v_b.reset();
}
void gprs_rlc_dl_window::set_sns(uint16_t sns)
{
OSMO_ASSERT(sns >= RLC_GPRS_SNS);
OSMO_ASSERT(sns <= RLC_MAX_SNS);
/* check for 2^n */
OSMO_ASSERT((sns & (-sns)) == sns);
m_sns = sns;
}
void gprs_rlc_dl_window::set_ws(uint16_t ws)
{
OSMO_ASSERT(ws >= RLC_GPRS_SNS/2);
OSMO_ASSERT(ws <= RLC_MAX_SNS/2);
m_ws = ws;
}
int gprs_rlc_dl_window::resend_needed()
{
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = this->mod_sns(bsn + 1)) {
if (m_v_b.is_nacked(bsn) || m_v_b.is_resend(bsn))
return bsn;
}
return -1;
}
int gprs_rlc_dl_window::mark_for_resend()
{
int resend = 0;
for (uint16_t bsn = v_a(); bsn != v_s(); bsn = this->mod_sns(bsn + 1)) {
if (m_v_b.is_unacked(bsn)) {
/* mark to be re-send */
m_v_b.mark_resend(bsn);
resend += 1;
}
}
return resend;
}
int gprs_rlc_dl_window::count_unacked()
{
uint16_t unacked = 0;
uint16_t bsn;
for (bsn = v_a(); bsn != v_s(); bsn = this->mod_sns(bsn + 1)) {
if (!m_v_b.is_acked(bsn))
unacked += 1;
}
return unacked;
}
static uint16_t bitnum_to_bsn(int bitnum, uint16_t ssn)
{
return (ssn - 1 - bitnum);
}
void gprs_rlc_dl_window::update(BTS *bts, char *show_rbb, uint16_t ssn,
uint16_t *lost, uint16_t *received)
{
/* SSN - 1 is in range V(A)..V(S)-1 */
for (int bitpos = 0; bitpos < ws(); bitpos++) {
uint16_t bsn = this->mod_sns(bitnum_to_bsn(bitpos, ssn));
if (bsn == this->mod_sns(v_a() - 1))
break;
if (show_rbb[ws() - 1 - bitpos] == 'R') {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
if (!m_v_b.is_acked(bsn))
*received += 1;
m_v_b.mark_acked(bsn);
} else {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
m_v_b.mark_nacked(bsn);
bts->rlc_nacked();
*lost += 1;
}
}
}
void extract_egprs_crbb_urbb(uint16_t uncomp_length, const uint8_t *uncomp_bitmap, char *show_rbb)
{
for (int i = 0; i < uncomp_length; i++) {
uint8_t bit;
bit = !!(uncomp_bitmap[i/8] & (1<<(7-i%8)));
show_rbb[i] = bit ? 'R' : 'I';
}
show_rbb[uncomp_length] = '\0';
}
void extract_egprs_urbb(uint16_t uncomp_length, const uint8_t *uncomp_bitmap, char *show_rbb,uint16_t start_index)
{
for (int i = 0; i < uncomp_length; i++) {
uint8_t bit;
bit = !!(uncomp_bitmap[i/8] & (1<<(7-i%8)));
show_rbb[start_index+uncomp_length-i] = bit ? 'R' : 'I';
}
show_rbb[uncomp_length] = '\0';
}
int search_runlen(
Node *root, /* root of Ones or Zeros tree */
uint8_t* bmbuf, /* Received compressed bitmap buf */
uint8_t bit_pos, /* the start bit pos to read codeword */
uint8_t* len_codewd, /* length of codeword */
uint16_t* rlen /* run length of Ones or Zeros */
)
{
Node* iter;
uint8_t dir;
iter = root;
*len_codewd = 0;
while (iter->run_length == 0) {
if ((iter->left == NULL)&& (iter->right == NULL))
return -1;
/* get the bit value at the bitpos and put it in right most of dir */
dir = (bmbuf[BITS_TO_BYTES(bit_pos)-1]>>(7-(MOD8(bit_pos))))&0x01;
(bit_pos)++;
(*len_codewd)++;
if (((dir&0x01) == 0) && (iter->left != NULL))
iter = iter->left;
else if (((dir&0x01) == 1) && (iter->right != NULL))
iter = iter->right;
else
return -1;
}
(*rlen) = *(iter->run_length);
return 1;
} /* search_runlen */
void gprs_rlc_dl_window::decompress_crbb(
BTS *bts,
int8_t compress_bmap_len, /* compressed bitmap length */
uint8_t clr_code_bit, /* run length of Ones or Zeros */
uint8_t* orig_buf, /* received block bitmap */
int16_t orig_bmaplen, /* bitmap length of Ack/Nack descr */
uint16_t* decompress_bmap_len, /* total bitmap length after decompression */
uint8_t* uncompress_bmbuf, /* bitmap after decompression */
bitvec *dest
)
{
uint8_t bit_pos = 0;
uint8_t nbits = 0; /* number of bits of codeword */
uint16_t run_length = 0;
uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */
unsigned wp = 0;
*decompress_bmap_len = 0;
int8_t Lc = compress_bmap_len;
while (compress_bmap_len >= 0) {
if (clr_code_bit == 1) {
search_runlen (bts->ones_list, orig_buf, bit_pos, &nbits, &run_length);
//If run length > 64, need makeup and terminating code
if (run_length < 64) {
clr_code_bit = 0;
}
cbmaplen= cbmaplen + run_length;
/* put run length of Ones in uncompressed bitmap */
while (run_length !=0) {
if (run_length > 8) {
bitvec_write_field(dest, wp, 0xff, 8);
run_length = run_length -8;
}
else {
bitvec_write_field(dest, wp, 0xff, run_length);
run_length = 0;
}
}
}
else {
search_runlen (bts->zeros_list, orig_buf, bit_pos, &nbits, &run_length);
//If run length > 64, need makeup and terminating code
if (run_length < 64) {
clr_code_bit = 1;
}
cbmaplen= cbmaplen + run_length;
/* put run length of Zeros in uncompressed bitmap */
while (run_length !=0) {
if (run_length > 8) {
bitvec_write_field(dest, wp, 0x00, 8);
run_length = run_length -8;
}
else {
bitvec_write_field(dest, wp, 0x00, run_length);
run_length = 0;
}
}
}
bit_pos = bit_pos + nbits;
compress_bmap_len = compress_bmap_len - nbits;
}
/* Decompress_bmap_len is the len of uncompressed bitmap
+ Original bitmap len of ack/nack desc
- Original compressed bitmap len
==> this is requird in extract rbb func*/
(*decompress_bmap_len) = cbmaplen + orig_bmaplen - Lc - 23;
return ;
}/* Decompress_CRBB */
void gprs_rlc_dl_window::egprs_update(BTS *bts, char *show_rbb,
EGPRS_AckNack_Desc_t *Egprs_Desc, uint16_t *lost,
uint16_t *received, int16_t len)
{
int16_t ssn = Egprs_Desc->STARTING_SEQUENCE_NUMBER;
uint8_t bow = Egprs_Desc->BEGINNING_OF_WINDOW;
uint8_t eow = Egprs_Desc->END_OF_WINDOW;
uint16_t uncomp_len = 0; /* total bitmap length of compressed part after
decompcompress plus uncompressed part */
uint8_t uncomp_bitmap[128];
uint16_t crbb_urbb_len = 0; /* bitmap length of compressed part after decompression */
uint16_t urbb_len;
int8_t Lc = Egprs_Desc->CRBB_LENGTH;
bitvec dest;
dest.data = uncomp_bitmap;
dest.cur_bit = 0;
dest.data_len = 128;
if(len > 0) {
urbb_len = len - Lc;
}
else {
urbb_len = Egprs_Desc->URBB_LENGTH;
}
if(Egprs_Desc->Exist_CRBB) {
LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist, "
"CRBB LEN =%d and Starting color code =%d",
Lc, Egprs_Desc->CRBB_STARTING_COLOR_CODE);
decompress_crbb(bts,
Lc,
Egprs_Desc->CRBB_STARTING_COLOR_CODE,
Egprs_Desc->CRBB,
len, //Ack Nack desc length
&uncomp_len,
uncomp_bitmap,
&dest);
/* now attach unCompressed bitmap part to the decompressed bitmap
* in unCompBitmap array if there is any */
/* if (Lc != 0) {
ubmaplen = acknack_len - Lc - 23;
}
else {
ubmaplen = acknack_len - 15;
}*/
crbb_urbb_len = dest.cur_bit;
extract_egprs_crbb_urbb(crbb_urbb_len, uncomp_bitmap, show_rbb);
LOGP(DRLCMACDL, LOGL_DEBUG, "crbb len %d uncomp len %d\n",Lc,crbb_urbb_len);
}
/* uncompressed part */
if ((urbb_len !=0) && (Egprs_Desc->URBB != (uint8_t *)NULL)) {
extract_egprs_urbb(urbb_len, Egprs_Desc->URBB, show_rbb, crbb_urbb_len);
LOGP(DRLCMACDL, LOGL_DEBUG, "urbb len %d\n" ,urbb_len);
}
/* if Beginning of window is set 1, Mark Acked between SSN-2 ( V(Q)-1) to V(A)*/
if (bow) {
for(int i = (v_a() -1); i < (ssn -2); i++ ) {
uint16_t bsn = this->mod_sns(i);
*received += 1;
m_v_b.mark_acked(bsn);
}
/* ssn -1 which is V(Q) should be nacked */
uint16_t bsn = ((2048 + (ssn-1)) & 0x07FF);/* MOD 2048 (MAX BSN NUM) */
m_v_b.mark_nacked(bsn);
bts->rlc_nacked();
*lost += 1;
}
/* SSN - 1 is in range V(A)..V(S)-1 */
for (int bitpos = 0; bitpos < crbb_urbb_len + urbb_len; bitpos++) {
uint16_t bsn = mod_sns(ssn + bitpos);
if (mod_sns(v_s() -bsn) >= distance())
break;
if (show_rbb[bitpos] == 'R') {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn);
if (!m_v_b.is_acked(bsn))
*received += 1;
m_v_b.mark_acked(bsn);
} else {
LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn);
m_v_b.mark_nacked(bsn);
bts->rlc_nacked();
*lost += 1;
}
}
/* if EOW is set, nack data btw last BSN indicated in the bitmap and
* the end of tx window V(S) */
if(eow) {
/* Currently EOW is not handled
for (int i = ssn + crbb_urbb_len + uncomp_len; bsn < v_s(); i++)
uint16_t bsn = mod_sns(ssn + i);
m_v_b.mark_nacked(bsn);
bts->rlc_nacked();
*lost += 1;
*/
}
}
int gprs_rlc_dl_window::move_window()
{
int i;
uint16_t bsn;
int moved = 0;
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = this->mod_sns(bsn + 1)) {
if (m_v_b.is_acked(bsn)) {
m_v_b.mark_invalid(bsn);
moved += 1;
} else
break;
}
return moved;
}
void gprs_rlc_dl_window::show_state(char *show_v_b)
{
int i;
uint16_t bsn;
for (i = 0, bsn = v_a(); bsn != v_s(); i++, bsn = this->mod_sns(bsn + 1)) {
uint16_t index = bsn & mod_sns_half();
switch(m_v_b.get_state(index)) {
case GPRS_RLC_DL_BSN_INVALID:
show_v_b[i] = 'I';
break;
case GPRS_RLC_DL_BSN_ACKED:
show_v_b[i] = 'A';
break;
case GPRS_RLC_DL_BSN_RESEND:
show_v_b[i] = 'X';
break;
case GPRS_RLC_DL_BSN_NACKED:
show_v_b[i] = 'N';
break;
default:
show_v_b[i] = '?';
}
}
show_v_b[i] = '\0';
}
void gprs_rlc_v_n::reset()
{
for (size_t i = 0; i < ARRAY_SIZE(m_v_n); ++i)
m_v_n[i] = GPRS_RLC_UL_BSN_INVALID;
}
void gprs_rlc_ul_window::set_sns(uint16_t sns)
{
OSMO_ASSERT(sns >= RLC_GPRS_SNS);
OSMO_ASSERT(sns <= RLC_MAX_SNS);
/* check for 2^n */
OSMO_ASSERT((sns & (-sns)) == sns);
m_sns = sns;
}
void gprs_rlc_ul_window::set_ws(uint16_t ws)
{
OSMO_ASSERT(ws >= RLC_GPRS_SNS/2);
OSMO_ASSERT(ws <= RLC_MAX_SNS/2);
m_ws = ws;
}
/* Update the receive block bitmap */
void gprs_rlc_ul_window::update_rbb(char *rbb)
{
int i;
for (i=0; i < ws(); i++) {
if (m_v_n.is_received(ssn()-1-i))
rbb[ws()-1-i] = 'R';
else
rbb[ws()-1-i] = 'I';
}
}
/* Update the receive block bitmap */
uint16_t gprs_rlc_ul_window::update_egprs_rbb(char *rbb)
{
int i;
uint16_t bsn;
for (i = 0, bsn = (v_q()+1); ((bsn < (v_r())) && (i < ws())); i++, bsn = this->mod_sns(bsn + 1)) {
//if (m_v_n.is_received(ssn()-1-i))
if (m_v_n.is_received(bsn)) //bsn
//rbb[ws()-1-i] = 'R';
rbb[i] = 'R'; //i
else
rbb[i] = 'I';
}
LOGP(DRLCMACUL, LOGL_DEBUG, "V(N):in update_egprs_rbb \"%s\" R=Received "
"I=Invalid\n", rbb);
return i;
}
/* Raise V(R) to highest received sequence number not received. */
void gprs_rlc_ul_window::raise_v_r(const uint16_t bsn)
{
uint16_t offset_v_r;
offset_v_r = this->mod_sns(bsn + 1 - v_r());
/* Positive offset, so raise. */
if (offset_v_r < (sns() >> 1)) {
while (offset_v_r--) {
if (offset_v_r) /* all except the received block */
m_v_n.mark_missing(v_r());
raise_v_r_to(1);
}
LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n", v_r());
}
}
/*
* Raise V(Q) if possible. This is looped until there is a gap
* (non received block) or the window is empty.
*/
uint16_t gprs_rlc_ul_window::raise_v_q()
{
uint16_t count = 0;
while (v_q() != v_r()) {
if (!m_v_n.is_received(v_q()))
break;
LOGP(DRLCMACUL, LOGL_DEBUG, "- Taking block %d out, raising "
"V(Q) to %d\n", v_q(), this->mod_sns(v_q() + 1));
raise_v_q(1);
count += 1;
}
return count;
}
void gprs_rlc_ul_window::receive_bsn(const uint16_t bsn)
{
m_v_n.mark_received(bsn);
raise_v_r(bsn);
}
bool gprs_rlc_ul_window::invalidate_bsn(const uint16_t bsn)
{
bool was_valid = m_v_n.is_received(bsn);
m_v_n.mark_missing(bsn);
return was_valid;
}