L1 Interface (PCU side): Added functions for handling PhConnectInd and PhRaInd primitives.

Added functions for writing and sending Immediate Assignment message.
Modified TBF managment for handling Channel Request and Immediate Assignment  messages.
This commit is contained in:
Ivan Kluchnikov 2012-04-17 22:00:31 +04:00
parent 27482ba371
commit 5310d4542c
4 changed files with 153 additions and 26 deletions

View File

@ -21,6 +21,7 @@
#include <pcu_l1_if.h> #include <pcu_l1_if.h>
#include <Threads.h> #include <Threads.h>
#include <gprs_rlcmac.h> #include <gprs_rlcmac.h>
#include <gsmL1prim.h>
LLIST_HEAD(gprs_rlcmac_tbfs); LLIST_HEAD(gprs_rlcmac_tbfs);
void *rlcmac_tall_ctx; void *rlcmac_tall_ctx;
@ -255,9 +256,97 @@ void write_packet_uplink_assignment(BitVector * dest, uint8_t tfi, uint32_t tll
// dest->writeField(wp,0x0,1); // Measurement Mapping struct not present // dest->writeField(wp,0x0,1); // Measurement Mapping struct not present
} }
// GSM 04.08 9.1.18 Immediate assignment
int write_immediate_assignment(BitVector * dest, uint8_t downlink, uint8_t ra, uint32_t fn,
uint8_t ta, uint8_t tfi = 0, uint32_t tlli = 0)
{
unsigned wp = 0;
dest->writeField(wp,0x0,4); // Skip Indicator
dest->writeField(wp,0x6,4); // Protocol Discriminator
dest->writeField(wp,0x3F,8); // Immediate Assignment Message Type
// 10.5.2.25b Dedicated mode or TBF
dest->writeField(wp,0x0,1); // spare
dest->writeField(wp,0x0,1); // TMA : Two-message assignment: No meaning
dest->writeField(wp,downlink,1); // Downlink : Downlink assignment to mobile in packet idle mode
dest->writeField(wp,0x1,1); // T/D : TBF or dedicated mode: this message assigns a Temporary Block Flow (TBF).
dest->writeField(wp,0x0,4); // Page Mode
// GSM 04.08 10.5.2.25a Packet Channel Description
dest->writeField(wp,0x1,5); // Channel type
dest->writeField(wp,(l1fh->fl1h)->channel_info.tn,3); // TN
dest->writeField(wp,(l1fh->fl1h)->channel_info.tsc,3); // TSC
dest->writeField(wp,0x0,3); // non-hopping RF channel configuraion
dest->writeField(wp,(l1fh->fl1h)->channel_info.arfcn,10); // ARFCN
//10.5.2.30 Request Reference
dest->writeField(wp,ra,8); // RA
dest->writeField(wp,(fn / (26 * 51)) % 32,5); // T1'
dest->writeField(wp,fn % 51,6); // T3
dest->writeField(wp,fn % 26,5); // T2
// 10.5.2.40 Timing Advance
dest->writeField(wp,0x0,2); // spare
dest->writeField(wp,ta,6); // Timing Advance value
// No mobile allocation in non-hopping systems.
// A zero-length LV. Just write L=0.
dest->writeField(wp,0,8);
if (downlink)
{
// GSM 04.08 10.5.2.16 IA Rest Octets
dest->writeField(wp, 3, 2); // "HH"
dest->writeField(wp, 1, 2); // "01" Packet Downlink Assignment
dest->writeField(wp,tlli,32); // TLLI
dest->writeField(wp,0x1,1); // switch TFI : on
dest->writeField(wp,tfi,5); // TFI
dest->writeField(wp,0x0,1); // RLC acknowledged mode
dest->writeField(wp,0x0,1); // ALPHA = present
dest->writeField(wp,0x0,5); // GAMMA power control parameter
dest->writeField(wp,0x0,1); // Polling Bit
dest->writeField(wp,0x1,1); // TA_VALID ???
dest->writeField(wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on
dest->writeField(wp,0x0,4); // TIMING_ADVANCE_INDEX
dest->writeField(wp,0x0,1); // TBF Starting TIME present
dest->writeField(wp,0x0,1); // P0 not present
dest->writeField(wp,0x1,1); // P0 not present
dest->writeField(wp,0xb,4);
}
else
{
// GMS 04.08 10.5.2.37b 10.5.2.16
dest->writeField(wp, 3, 2); // "HH"
dest->writeField(wp, 0, 2); // "0" Packet Uplink Assignment
dest->writeField(wp, 1, 1); // Block Allocation : Not Single Block Allocation
dest->writeField(wp, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity
dest->writeField(wp, 0, 1); // POLLING
dest->writeField(wp, 0, 1); // ALLOCATION_TYPE: dynamic
dest->writeField(wp, 1, 3); // USF
dest->writeField(wp, 1, 1); // USF_GRANULARITY
dest->writeField(wp, 0 , 1); // "0" power control: Not Present
dest->writeField(wp, 0, 2); // CHANNEL_CODING_COMMAND
dest->writeField(wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING
dest->writeField(wp, 1 , 1); // "1" Alpha : Present
dest->writeField(wp, 0, 4); // Alpha
dest->writeField(wp, 0, 5); // Gamma
dest->writeField(wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG
dest->writeField(wp, 0, 1); // TBF_STARTING_TIME_FLAG
}
if (wp%8)
return wp/8+1;
else
return wp/8;
}
void write_ia_rest_octets_downlink_assignment(BitVector * dest, uint8_t tfi, uint32_t tlli) void write_ia_rest_octets_downlink_assignment(BitVector * dest, uint8_t tfi, uint32_t tlli)
{ {
// GMS 04.08 10.5.2.16 // GSM 04.08 10.5.2.16
unsigned wp = 0; unsigned wp = 0;
dest->writeField(wp, 3, 2); // "HH" dest->writeField(wp, 3, 2); // "HH"
dest->writeField(wp, 1, 2); // "01" Packet Downlink Assignment dest->writeField(wp, 1, 2); // "01" Packet Downlink Assignment
@ -326,7 +415,7 @@ void gprs_rlcmac_tx_ul_ack(uint8_t tfi, uint32_t tlli, RlcMacUplinkDataBlock_t *
decode_gsm_rlcmac_downlink(&packet_uplink_ack_vec, packet_uplink_ack); decode_gsm_rlcmac_downlink(&packet_uplink_ack_vec, packet_uplink_ack);
free(packet_uplink_ack); free(packet_uplink_ack);
COUT("RLCMAC_CONTROL_BLOCK_END------------------------------"); COUT("RLCMAC_CONTROL_BLOCK_END------------------------------");
pcu_l1if_tx(&packet_uplink_ack_vec); pcu_l1if_tx(&packet_uplink_ack_vec, GsmL1_Sapi_Pacch);
} }
void gprs_rlcmac_data_block_parse(gprs_rlcmac_tbf* tbf, RlcMacUplinkDataBlock_t * ul_data_block) void gprs_rlcmac_data_block_parse(gprs_rlcmac_tbf* tbf, RlcMacUplinkDataBlock_t * ul_data_block)
@ -373,14 +462,7 @@ int gprs_rlcmac_rcv_data_block(BitVector *rlc_block)
tbf = tbf_by_tfi(ul_data_block->TFI); tbf = tbf_by_tfi(ul_data_block->TFI);
if (!tbf) { if (!tbf) {
tbf = tbf_alloc(ul_data_block->TFI); return 0;
if (tbf) {
tbf->tlli = ul_data_block->TLLI;
tbf->direction = GPRS_RLCMAC_UL_TBF;
tbf->state = GPRS_RLCMAC_WAIT_DATA_SEQ_START;
} else {
return 0;
}
} }
switch (tbf->state) { switch (tbf->state) {
@ -433,12 +515,6 @@ int gprs_rlcmac_rcv_control_block(BitVector *rlc_block)
decode_gsm_rlcmac_uplink(rlc_block, ul_control_block); decode_gsm_rlcmac_uplink(rlc_block, ul_control_block);
COUT("RLCMAC_CONTROL_BLOCK_END------------------------------"); COUT("RLCMAC_CONTROL_BLOCK_END------------------------------");
//gprs_rlcmac_control_block_get_tfi_tlli(ul_control_block, &tfi, &tlli);
//tbf = tbf_by_tfi(tfi);
//if (!tbf) {
// return 0;
//}
switch (ul_control_block->u.MESSAGE_TYPE) { switch (ul_control_block->u.MESSAGE_TYPE) {
case MT_PACKET_CONTROL_ACK: case MT_PACKET_CONTROL_ACK:
tlli = ul_control_block->u.Packet_Control_Acknowledgement.TLLI; tlli = ul_control_block->u.Packet_Control_Acknowledgement.TLLI;
@ -459,7 +535,7 @@ int gprs_rlcmac_rcv_control_block(BitVector *rlc_block)
BitVector packet_uplink_assignment(23*8); BitVector packet_uplink_assignment(23*8);
packet_uplink_assignment.unhex("2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); packet_uplink_assignment.unhex("2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
write_packet_uplink_assignment(&packet_uplink_assignment, tbf->tfi, tbf->tlli); write_packet_uplink_assignment(&packet_uplink_assignment, tbf->tfi, tbf->tlli);
pcu_l1if_tx(&packet_uplink_assignment); pcu_l1if_tx(&packet_uplink_assignment, GsmL1_Sapi_Pacch);
break; break;
} }
free(ul_control_block); free(ul_control_block);
@ -485,6 +561,27 @@ void gprs_rlcmac_rcv_block(BitVector *rlc_block)
} }
} }
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, uint16_t ta)
{
struct gprs_rlcmac_tbf *tbf;
// Create new TBF
int tfi = tfi_alloc();
if (tfi < 0) {
return tfi;
}
tbf = tbf_alloc(tfi);
tbf->direction = GPRS_RLCMAC_UL_TBF;
tbf->state = GPRS_RLCMAC_WAIT_DATA_SEQ_START;
COUT("[UPLINK TBF : " << tfi << " ] : START");
COUT("SEND Immidiate Assignment>>>>>>>>>>>>>>>>>>");
BitVector immediate_assignment(23*8);
immediate_assignment.unhex("2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
int len = write_immediate_assignment(&immediate_assignment, 0, ra, Fn, ta, tbf->tfi);
pcu_l1if_tx(&immediate_assignment, GsmL1_Sapi_Agch, len);
}
// Send RLC data to OpenBTS. // Send RLC data to OpenBTS.
void gprs_rlcmac_tx_dl_data_block(uint32_t tlli, uint8_t tfi, uint8_t *pdu, int start_index, int end_index, uint8_t bsn, uint8_t fbi) void gprs_rlcmac_tx_dl_data_block(uint32_t tlli, uint8_t tfi, uint8_t *pdu, int start_index, int end_index, uint8_t bsn, uint8_t fbi)
{ {
@ -521,7 +618,7 @@ void gprs_rlcmac_tx_dl_data_block(uint32_t tlli, uint8_t tfi, uint8_t *pdu, int
} }
encode_gsm_rlcmac_downlink_data(&data_block_vector, data_block); encode_gsm_rlcmac_downlink_data(&data_block_vector, data_block);
free(data_block); free(data_block);
pcu_l1if_tx(&data_block_vector); pcu_l1if_tx(&data_block_vector, GsmL1_Sapi_Pdtch);
} }
int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf) int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf)
@ -589,9 +686,9 @@ void gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf)
void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf) void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf)
{ {
COUT("SEND IA Rest Octets Downlink Assignment>>>>>>>>>>>>>>>>>>"); COUT("SEND IA Rest Octets Downlink Assignment>>>>>>>>>>>>>>>>>>");
BitVector ia_rest_octets_downlink_assignment(23*8); BitVector immediate_assignment(23*8);
ia_rest_octets_downlink_assignment.unhex("2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); immediate_assignment.unhex("2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
write_ia_rest_octets_downlink_assignment(&ia_rest_octets_downlink_assignment, tbf->tfi, tbf->tlli); int len = write_immediate_assignment(&immediate_assignment, 1, 125, get_current_fn(), (l1fh->fl1h)->channel_info.ta, tbf->tfi, tbf->tlli);
pcu_l1if_tx(&ia_rest_octets_downlink_assignment); pcu_l1if_tx(&immediate_assignment, GsmL1_Sapi_Agch, len);
tbf_gsm_timer_start(tbf, 0, 120); tbf_gsm_timer_start(tbf, 0, 120);
} }

View File

@ -89,6 +89,8 @@ int gprs_rlcmac_rcv_control_block(BitVector *rlc_block);
void gprs_rlcmac_rcv_block(BitVector *rlc_block); void gprs_rlcmac_rcv_block(BitVector *rlc_block);
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, uint16_t ta);
void gprs_rlcmac_tx_dl_data_block(uint32_t tlli, uint8_t tfi, uint8_t *pdu, int start_index, int end_index, uint8_t bsn, uint8_t fbi); void gprs_rlcmac_tx_dl_data_block(uint32_t tlli, uint8_t tfi, uint8_t *pdu, int start_index, int end_index, uint8_t bsn, uint8_t fbi);
int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf); int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf);

View File

@ -59,6 +59,7 @@ struct msgb *gen_dummy_msg(void)
// RLC/MAC filler with USF=1 // RLC/MAC filler with USF=1
BitVector filler("0100000110010100001010110010101100101011001010110010101100101011001010110010101100101011001010110010101100101011001010110010101100101011001010110010101100101011001010110010101100101011"); BitVector filler("0100000110010100001010110010101100101011001010110010101100101011001010110010101100101011001010110010101100101011001010110010101100101011001010110010101100101011001010110010101100101011");
prim->id = GsmL1_PrimId_PhDataReq; prim->id = GsmL1_PrimId_PhDataReq;
prim->u.phDataReq.sapi = GsmL1_Sapi_Pacch;
filler.pack((unsigned char*)&(prim->u.phDataReq.msgUnitParam.u8Buffer[ofs])); filler.pack((unsigned char*)&(prim->u.phDataReq.msgUnitParam.u8Buffer[ofs]));
ofs += filler.size() >> 3; ofs += filler.size() >> 3;
prim->u.phDataReq.msgUnitParam.u8Size = ofs; prim->u.phDataReq.msgUnitParam.u8Size = ofs;
@ -66,7 +67,7 @@ struct msgb *gen_dummy_msg(void)
} }
// Send RLC/MAC block to OpenBTS. // Send RLC/MAC block to OpenBTS.
void pcu_l1if_tx(BitVector * block) void pcu_l1if_tx(BitVector * block, GsmL1_Sapi_t sapi, int len)
{ {
int ofs = 0; int ofs = 0;
struct msgb *msg = l1p_msgb_alloc(); struct msgb *msg = l1p_msgb_alloc();
@ -75,9 +76,10 @@ void pcu_l1if_tx(BitVector * block)
GsmL1_Prim_t *prim = msgb_l1prim(msg); GsmL1_Prim_t *prim = msgb_l1prim(msg);
prim->id = GsmL1_PrimId_PhDataReq; prim->id = GsmL1_PrimId_PhDataReq;
prim->u.phDataReq.sapi = sapi;
block->pack((unsigned char*)&(prim->u.phDataReq.msgUnitParam.u8Buffer[ofs])); block->pack((unsigned char*)&(prim->u.phDataReq.msgUnitParam.u8Buffer[ofs]));
ofs += block->size() >> 3; ofs += block->size() >> 3;
prim->u.phDataReq.msgUnitParam.u8Size = ofs; prim->u.phDataReq.msgUnitParam.u8Size = len;
COUT("Add Block to WRITE QUEUE: " << *block); COUT("Add Block to WRITE QUEUE: " << *block);
osmo_wqueue_enqueue(queue, msg); osmo_wqueue_enqueue(queue, msg);
@ -92,6 +94,15 @@ int pcu_l1if_rx_pdch(GsmL1_PhDataInd_t *data_ind)
gprs_rlcmac_rcv_block(block); gprs_rlcmac_rcv_block(block);
} }
static int handle_ph_connect_ind(struct femtol1_hdl *fl1, GsmL1_PhConnectInd_t *connect_ind)
{
(l1fh->fl1h)->channel_info.arfcn = connect_ind->u16Arfcn;
(l1fh->fl1h)->channel_info.tn = connect_ind->u8Tn;
(l1fh->fl1h)->channel_info.tsc = connect_ind->u8Tsc;
COUT("RX: [ PCU <- BTS ] PhConnectInd: ARFCN: " << connect_ind->u16Arfcn
<<" TN: " << (unsigned)connect_ind->u8Tn << " TSC: " << (unsigned)connect_ind->u8Tsc);
}
static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, GsmL1_PhReadyToSendInd_t *readytosend_ind) static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, GsmL1_PhReadyToSendInd_t *readytosend_ind)
{ {
struct msgb *resp_msg; struct msgb *resp_msg;
@ -134,6 +145,14 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
return rc; return rc;
} }
static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind)
{
int rc = 0;
(l1fh->fl1h)->channel_info.ta = ra_ind->measParam.i16BurstTiming;
rc = gprs_rlcmac_rcv_rach(ra_ind->msgUnitParam.u8Buffer[0], ra_ind->u32Fn, ra_ind->measParam.i16BurstTiming);
return rc;
}
/* handle any random indication from the L1 */ /* handle any random indication from the L1 */
int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1, struct msgb *msg) int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1, struct msgb *msg)
{ {
@ -142,15 +161,16 @@ int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1, struct msgb *msg)
switch (l1p->id) { switch (l1p->id) {
case GsmL1_PrimId_PhConnectInd: case GsmL1_PrimId_PhConnectInd:
rc = handle_ph_connect_ind(fl1, &l1p->u.phConnectInd);
break; break;
case GsmL1_PrimId_PhReadyToSendInd: case GsmL1_PrimId_PhReadyToSendInd:
rc = handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd); rc = handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd);
break; break;
case GsmL1_PrimId_PhDataInd: case GsmL1_PrimId_PhDataInd:
COUT("RX GsmL1_PrimId_PhDataInd ");
rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd); rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd);
break; break;
case GsmL1_PrimId_PhRaInd: case GsmL1_PrimId_PhRaInd:
rc = handle_ph_ra_ind(fl1, &l1p->u.phRaInd);
break; break;
default: default:
break; break;

View File

@ -47,6 +47,14 @@ struct femtol1_hdl {
struct osmo_fd read_ofd; /* osmo file descriptors */ struct osmo_fd read_ofd; /* osmo file descriptors */
struct osmo_wqueue write_q; struct osmo_wqueue write_q;
struct {
uint16_t arfcn;
uint8_t tn;
uint8_t tsc;
uint16_t ta;
} channel_info;
}; };
struct l1fwd_hdl { struct l1fwd_hdl {
@ -62,7 +70,7 @@ extern struct l1fwd_hdl *l1fh;
int get_current_fn(); int get_current_fn();
void pcu_l1if_tx(BitVector * block); void pcu_l1if_tx(BitVector * block, GsmL1_Sapi_t sapi, int len = 23);
int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1h, struct msgb *msg); int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1h, struct msgb *msg);