Commit 41c60711 authored by Cedric Roux's avatar Cedric Roux

Basic support of FAPI interface.

This commit permits one UE to connect.
It implements some very basic support for
SchedDlTriggerReq and SchedDlConfigInd
(and also a bit SchedDlRlcBufferReq)
(see schedule_ue_spec).

There are many assumptions everywhere.
This is very preliminary work.
parent 2aab8b6d
...@@ -65,6 +65,10 @@ ...@@ -65,6 +65,10 @@
# include "intertask_interface.h" # include "intertask_interface.h"
#endif #endif
#ifdef FAPI
#include "ff-mac.h"
#endif
#define ENABLE_MAC_PAYLOAD_DEBUG #define ENABLE_MAC_PAYLOAD_DEBUG
//#define DEBUG_eNB_SCHEDULER 1 //#define DEBUG_eNB_SCHEDULER 1
...@@ -415,6 +419,154 @@ set_ul_DAI( ...@@ -415,6 +419,154 @@ set_ul_DAI(
} }
} }
#ifdef FAPI
//------------------------------------------------------------------------------
void schedule_ue_spec(
module_id_t module_idP,
frame_t frameP,
sub_frame_t subframeP,
unsigned int *nb_rb_used0,
unsigned int *nCCE_used,
int* mbsfn_flag)
//------------------------------------------------------------------------------
{
fapi_interface_t *fapi = eNB_mac_inst[module_idP].fapi;
struct SchedDlRlcBufferReqParameters rlc;
struct SchedDlTriggerReqParameters req;
struct SchedDlConfigIndParameters ind;
int UE_id;
mac_rlc_status_resp_t rlc_status;
eNB_MAC_INST *eNB = &eNB_mac_inst[module_idP];
UE_list_t *UE_list = &eNB->UE_list;
uint16_t sdu_length;
uint8_t sdu_lcid;
struct BuildDataListElement_s *d;
unsigned char dlsch_buffer[MAX_DLSCH_PAYLOAD_BYTES];
int offset;
void *DLSCH_dci;
DCI_PDU *DCI_pdu = &eNB->common_channels[0 /* CC_id */].DCI_pdu;
/* let's only schedule subframe 2 for the moment */
if (subframeP != 2) return;
/* hack to set has_ue == 1 in the scheduler */
{
void has_ue(void *, int);
if (UE_list->head != -1) has_ue(fapi->sched, UE_RNTI(module_idP, UE_list->head));
}
/* update RLC buffers status in the scheduler */
for (UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
memset(&rlc, 0, sizeof(rlc));
rlc.rnti = UE_RNTI(module_idP, UE_id);
/* this code is wrong. We should have an RLC function "get_buffer_occupancy" */
/* in the meantime let's pretend we ask for 20 bytes */
/* plus we should loop over all configured RaB */
/* DCCH (srb 1, lcid 1) */
rlc_status = mac_rlc_status_ind(module_idP, rlc.rnti, 0 /* eNB_index */,
frameP, 1 /* enb_flagP */, 0 /* MBMS_flagP */, DCCH, 20);
rlc.logicalChannelIdentity = DCCH;
rlc.rlcTransmissionQueueSize = rlc_status.bytes_in_buffer;
SchedDlRlcBufferReq(fapi->sched, &rlc);
/* DCCH+1 (srb 2, lcid 2) */
rlc_status = mac_rlc_status_ind(module_idP, rlc.rnti, 0 /* eNB_index */,
frameP, 1 /* enb_flagP */, 0 /* MBMS_flagP */, DCCH+1, 20);
rlc.logicalChannelIdentity = DCCH+1;
rlc.rlcTransmissionQueueSize = rlc_status.bytes_in_buffer;
SchedDlRlcBufferReq(fapi->sched, &rlc);
/* DTCH (drb 1, lcid 3) */
rlc_status = mac_rlc_status_ind(module_idP, rlc.rnti, 0 /* eNB_index */,
frameP, 1 /* enb_flagP */, 0 /* MBMS_flagP */, DTCH, 20);
rlc.logicalChannelIdentity = DTCH;
rlc.rlcTransmissionQueueSize = rlc_status.bytes_in_buffer;
SchedDlRlcBufferReq(fapi->sched, &rlc);
}
SchedDlTriggerReq(fapi->sched, &req);
SchedDlConfigInd(fapi, &ind);
if (ind.nr_buildDataList == 0) return;
/*LOG_D*/LOG_I(MAC, "we have something to schedule!!\n");
/* let's process only UE_id == 0 for the moment */
UE_id = 0;
d = &ind.buildDataList[0];
/* we suppose 1 RLC PDU - let's crash if it's not the case */
if (d->nr_rlcPDU_List != 1) { LOG_E(MAC, "this should not happen\n"); abort(); }
sdu_lcid = d->rlcPduList[0][0].logicalChannelIdentity;
sdu_length = mac_rlc_data_req(
module_idP,
d->rnti,
module_idP,
frameP,
ENB_FLAG_YES,
MBMS_FLAG_NO,
d->rlcPduList[0][0].logicalChannelIdentity,
(char *)dlsch_buffer);
/*LOG_D*/LOG_I(MAC, "got sdu length %d\n", sdu_length);
offset = generate_dlsch_header(
(unsigned char*)UE_list->DLSCH_pdu[0][0][UE_id].payload[0],
1, /* num sdu */
&sdu_length,
&sdu_lcid,
255, /* no rdx */
0, /* timing advance */
NULL, /* contention res id */
0, /* padding */
32-2-1-sdu_length); /* post padding */
/*LOG_D*/LOG_I(MAC, "offset %d\n", offset);
memcpy(&UE_list->DLSCH_pdu[0 /* CC_id */][0][UE_id].payload[0][offset],
dlsch_buffer,
sdu_length);
add_ue_dlsch_info(module_idP,
0, /* CC_id */
UE_id,
subframeP,
S_DL_SCHEDULED);
DLSCH_dci = (void *)UE_list->UE_template[0 /*CC_id*/][UE_id].DLSCH_DCI[d->dci.harqProcess];
/* only 5MHz FDD format1 for the moment */
if (d->dci.format != ONE) { LOG_E(MAC, "bad dci format\n"); abort(); }
((DCI1_5MHz_FDD_t*)DLSCH_dci)->mcs = d->dci.mcs[0];
((DCI1_5MHz_FDD_t*)DLSCH_dci)->harq_pid = d->dci.harqProcess;
((DCI1_5MHz_FDD_t*)DLSCH_dci)->ndi = d->dci.ndi[0];
((DCI1_5MHz_FDD_t*)DLSCH_dci)->rv = d->dci.rv[0];
((DCI1_5MHz_FDD_t*)DLSCH_dci)->TPC = d->dci.tpc;
nCCE_used[0] = 1;
/* let's do the job of fill_DLSCH_dci */
eNB_dlsch_info[module_idP][0 /* CC_id */][UE_id].status = S_DL_WAITING;
((DCI1_5MHz_FDD_t*)DLSCH_dci)->rballoc = d->dci.rbBitmap;
((DCI1_5MHz_FDD_t*)DLSCH_dci)->rah = 0;
add_ue_spec_dci(DCI_pdu,
DLSCH_dci,
d->rnti,
sizeof(DCI1_5MHz_FDD_t),
d->dci.aggrLevel, /* process_ue_cqi (module_idP,UE_id),//aggregation, */
sizeof_DCI1_5MHz_FDD_t,
format1,
0);
}
#else /* FAPI */
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
...@@ -1506,9 +1658,15 @@ schedule_ue_spec( ...@@ -1506,9 +1658,15 @@ schedule_ue_spec(
} }
#endif /* FAPI */
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void void
#ifdef FAPI
fill_DLSCH_dci_old(
#else
fill_DLSCH_dci( fill_DLSCH_dci(
#endif
module_id_t module_idP, module_id_t module_idP,
frame_t frameP, frame_t frameP,
sub_frame_t subframeP, sub_frame_t subframeP,
...@@ -2423,6 +2581,26 @@ fill_DLSCH_dci( ...@@ -2423,6 +2581,26 @@ fill_DLSCH_dci(
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI,VCD_FUNCTION_OUT); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI,VCD_FUNCTION_OUT);
} }
#ifdef FAPI
//------------------------------------------------------------------------------
void
fill_DLSCH_dci(
module_id_t module_idP,
frame_t frameP,
sub_frame_t subframeP,
uint32_t* RBallocP,
uint8_t RA_scheduledP,
int* mbsfn_flagP
)
//------------------------------------------------------------------------------
{
if (subframeP != 2) return fill_DLSCH_dci_old(module_idP, frameP, subframeP, RBallocP, RA_scheduledP, mbsfn_flagP);
/* in subframe 2, nothing to do, schedule_spec_ue already called add_ue_spec_dci */
}
#endif /* FAPI */
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
unsigned char* unsigned char*
get_dlsch_sdu( get_dlsch_sdu(
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
#include "log.h" #include "log.h"
#include "assertions.h" #include "assertions.h"
#undef LOG_D //#undef LOG_D
#define LOG_D LOG_I //#define LOG_D LOG_I
#include <stdlib.h> #include <stdlib.h>
#include <pthread.h> #include <pthread.h>
...@@ -23,6 +23,7 @@ struct fapi { ...@@ -23,6 +23,7 @@ struct fapi {
volatile int req_id[N]; volatile int req_id[N];
volatile int rsp_id[N]; volatile int rsp_id[N];
struct CschedCellConfigCnfParameters CschedCellConfigCnfParameters; struct CschedCellConfigCnfParameters CschedCellConfigCnfParameters;
struct SchedDlConfigIndParameters SchedDlConfigIndParameters;
}; };
#define LOCK(fi, fn) do { \ #define LOCK(fi, fn) do { \
...@@ -63,7 +64,19 @@ struct fapi { ...@@ -63,7 +64,19 @@ struct fapi {
void SchedDlConfigInd(fapi_interface_t *_fi, struct SchedDlConfigIndParameters *params) void SchedDlConfigInd(fapi_interface_t *_fi, struct SchedDlConfigIndParameters *params)
{ {
struct fapi *fi = (struct fapi *)_fi;
int fn = 0; int fn = 0;
LOG_D(MAC, "SchedDlConfigInd enter\n");
LOCK(fi, fn);
WAIT(fi, fn);
*params = fi->SchedDlConfigIndParameters;
DONE_wrapper(fi, fn);
UNLOCK(fi, fn);
LOG_D(MAC, "SchedDlConfigInd leave\n");
} }
void SchedUlConfigInd(fapi_interface_t *_fi, struct SchedUlConfigIndParameters *params) void SchedUlConfigInd(fapi_interface_t *_fi, struct SchedUlConfigIndParameters *params)
...@@ -124,7 +137,19 @@ void CschedCellConfigUpdateInd(fapi_interface_t *_fi, struct CschedCellConfigUpd ...@@ -124,7 +137,19 @@ void CschedCellConfigUpdateInd(fapi_interface_t *_fi, struct CschedCellConfigUpd
void SchedDlConfigInd_callback(void *callback_data, const struct SchedDlConfigIndParameters *params) void SchedDlConfigInd_callback(void *callback_data, const struct SchedDlConfigIndParameters *params)
{ {
struct fapi *fi = callback_data;
int fn = 0; int fn = 0;
LOG_D(MAC, "SchedDlConfigInd_callback enter\n");
LOCK(fi, fn);
CHECK(fi, fn);
fi->SchedDlConfigIndParameters = *params;
DONE_callback(fi, fn);
UNLOCK(fi, fn);
LOG_D(MAC, "SchedDlConfigInd_callback leave\n");
} }
void SchedUlConfigInd_callback(void *callback_data, const struct SchedUlConfigIndParameters *params) void SchedUlConfigInd_callback(void *callback_data, const struct SchedUlConfigIndParameters *params)
......
...@@ -11,7 +11,10 @@ ...@@ -11,7 +11,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#define LOG(...) do { printf("minifapi:%s:%d: ", __FUNCTION__, __LINE__); printf(__VA_ARGS__); printf("\n"); } while (0) #define MIN(a, b) ((a) < (b) ? (a) : (b))
//#define LOG(...) do { printf("minifapi:%s:%d: ", __FUNCTION__, __LINE__); printf(__VA_ARGS__); printf("\n"); } while (0)
#define LOG(...) /**/
struct scheduler { struct scheduler {
void *callback_data; void *callback_data;
...@@ -24,8 +27,23 @@ struct scheduler { ...@@ -24,8 +27,23 @@ struct scheduler {
CschedUeReleaseCnf_callback_t *CschedUeReleaseCnf; CschedUeReleaseCnf_callback_t *CschedUeReleaseCnf;
CschedUeConfigUpdateInd_callback_t *CschedUeConfigUpdateInd; CschedUeConfigUpdateInd_callback_t *CschedUeConfigUpdateInd;
CschedCellConfigUpdateInd_callback_t *CschedCellConfigUpdateInd; CschedCellConfigUpdateInd_callback_t *CschedCellConfigUpdateInd;
/* below data is for testing purpose - it's hackish */
/* has_ue: hackishly set to 1 in schedule_ue_spec */
int has_ue;
/* the RNTI of the UE */
int ue_rnti;
/* the transmission queue size of each RLC logical channel for the UE */
int lc_rlc_queuesize[11];
int old_ndi;
}; };
/* hack function to set has_ue to 1 */
void has_ue(struct scheduler *s, int rnti)
{
s->has_ue = 1;
s->ue_rnti = rnti;
}
void *SchedInit( void *SchedInit(
void *callback_data, void *callback_data,
SchedDlConfigInd_callback_t *SchedDlConfigInd, SchedDlConfigInd_callback_t *SchedDlConfigInd,
...@@ -59,6 +77,8 @@ void *SchedInit( ...@@ -59,6 +77,8 @@ void *SchedInit(
ret->CschedUeConfigUpdateInd = CschedUeConfigUpdateInd; ret->CschedUeConfigUpdateInd = CschedUeConfigUpdateInd;
ret->CschedCellConfigUpdateInd = CschedCellConfigUpdateInd; ret->CschedCellConfigUpdateInd = CschedCellConfigUpdateInd;
ret->has_ue = 0;
LOG("leave"); LOG("leave");
return ret; return ret;
...@@ -68,6 +88,13 @@ void *SchedInit( ...@@ -68,6 +88,13 @@ void *SchedInit(
void SchedDlRlcBufferReq(void *_sched, const struct SchedDlRlcBufferReqParameters *params) void SchedDlRlcBufferReq(void *_sched, const struct SchedDlRlcBufferReqParameters *params)
{ {
struct scheduler *sched = _sched;
LOG("enter lcid %d queue size %d", params->logicalChannelIdentity, params->rlcTransmissionQueueSize);
sched->lc_rlc_queuesize[params->logicalChannelIdentity] = params->rlcTransmissionQueueSize;
LOG("leave");
} }
void SchedDlPagingBufferReq(void *_sched, const struct SchedDlPagingBufferReqParameters *params) void SchedDlPagingBufferReq(void *_sched, const struct SchedDlPagingBufferReqParameters *params)
...@@ -80,6 +107,72 @@ void SchedDlMacBufferReq(void *_sched, const struct SchedDlMacBufferReqParameter ...@@ -80,6 +107,72 @@ void SchedDlMacBufferReq(void *_sched, const struct SchedDlMacBufferReqParameter
void SchedDlTriggerReq(void *_sched, const struct SchedDlTriggerReqParameters *params) void SchedDlTriggerReq(void *_sched, const struct SchedDlTriggerReqParameters *params)
{ {
struct scheduler *sched = _sched;
struct SchedDlConfigIndParameters ind;
struct BuildDataListElement_s *d;
int lcid = -1;
LOG("enter frame %d subframe %d", params->sfnSf >> 4, params->sfnSf & 0xf);
ind.nr_buildDataList = 0;
ind.nr_buildRARList = 0;
ind.nr_buildBroadcastList = 0;
ind.nr_ofdmSymbolsCount = 0;
ind.nr_vendorSpecificList = 0;
ind.nr_ofdmSymbolsCount = 0;
/* basic scheduler: only one UE accepted, we send max 20 RLC bytes,
* only from one logical channel (srb1, srb2 or drb1, in that priority
* order), 5MHz, SISO, no retransmission (ACK/NACK processing not done)
*/
if (sched->lc_rlc_queuesize[1] == 0) goto no_srb1;
lcid = 1;
goto fill;
no_srb1:
if (sched->lc_rlc_queuesize[2] == 0) goto no_srb2;
lcid = 2;
goto fill;
no_srb2:
if (sched->lc_rlc_queuesize[3] == 0) goto no_sched;
lcid = 3;
fill:
ind.nr_ofdmSymbolsCount = 1;
ind.nr_buildDataList = 1;
d = &ind.buildDataList[0];
d->rnti = sched->ue_rnti;
/* fill DCI */
d->dci.rnti = d->rnti;
d->dci.rbBitmap = 0x1800; /* 1 1000 0000 0000 allocate the 2 low RBG = 4 RBs */
d->dci.rbShift = 0;
d->dci.resAlloc = 0;
d->dci.tbsSize[0] = 32;
d->dci.mcs[0] = 4;
d->dci.ndi[0] = 1 - sched->old_ndi; sched->old_ndi = 1 - sched->old_ndi; /* always new */
d->dci.rv[0] = 0;
d->dci.cceIndex = 0;
d->dci.aggrLevel = 1;
/* d->dci.precodingInfo not relevant */
d->dci.format = ONE;
d->dci.tpc = 0;
d->dci.harqProcess = 0; /* always use harq pid 0 */
/* d->dci.dai not relevant */
/* d->dci.vrbFormat not relevant */
/* d->dci.tbSwap not relevant */
d->dci.spsRelease = 0;
/* the rest of d->dci is not relevant */
d->ceBitmap[0] = 0;
d->nr_rlcPDU_List = 1;
d->rlcPduList[0][0].logicalChannelIdentity = lcid;
d->rlcPduList[0][0].size = MIN(sched->lc_rlc_queuesize[lcid], 20);
/* servCellIndex/activationDeactivationCE not set, not used for the moment */
no_sched:
sched->SchedDlConfigInd(sched->callback_data, &ind);
LOG("leave");
} }
void SchedDlRachInfoReq(void *_sched, const struct SchedDlRachInfoReqParameters *params) void SchedDlRachInfoReq(void *_sched, const struct SchedDlRachInfoReqParameters *params)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment